레이지 초기화graphql-spring에서 예외 발생
현재 REST-Server를 GraphQL로 마이그레이션하는 중입니다(적어도 부분적으로).대부분의 작업이 완료되었지만 해결할 수 없는 것처럼 보이는 이 문제를 우연히 발견했습니다. FetchType을 사용하는 graphql 쿼리에서 OneToMany 관계입니다.게으른.
저는 통합을 위해 https://github.com/graphql-java/graphql-spring-boot 과 https://github.com/graphql-java/graphql-java-tools 을 사용하고 있습니다.
다음은 예입니다.
엔티티:
@Entity
class Show {
private Long id;
private String name;
@OneToMany(mappedBy = "show")
private List<Competition> competition;
}
@Entity
class Competition {
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
private Show show;
}
스키마:
type Show {
id: ID!
name: String!
competitions: [Competition]
}
type Competition {
id: ID!
name: String
}
extend type Query {
shows : [Show]
}
해결 프로그램:
@Component
public class ShowResolver implements GraphQLQueryResolver {
@Autowired
private ShowRepository showRepository;
public List<Show> getShows() {
return ((List<Show>)showRepository.findAll());
}
}
이제 엔드포인트를 이 (바로 가기) 쿼리로 쿼리하는 경우:
{
shows {
id
name
competitions {
id
}
}
}
이해합니다:
기관.기관.기관.레이지 초기화예외: 역할 컬렉션을 게으르게 초기화하지 못했습니다.Show.competitions, 프록시를 초기화할 수 없음 - 세션 없음
이제 이 오류가 발생하는 이유와 의미를 알 수 있지만, 이 오류에 대한 수정 사항을 적용해야 하는지는 잘 모르겠습니다.저는 모든 관계를 적극적으로 가져오기 위해 제 단체를 만들고 싶지 않습니다. 왜냐하면 그것은 GraphQL의 장점 중 일부를 부정할 것이기 때문입니다.해결책을 찾아야 할 만한 아이디어가 있습니까?감사합니다!
제가 선호하는 해결책은 서블릿이 응답을 보낼 때까지 트랜잭션을 열어두는 것입니다.이 작은 코드 변경으로 LazyLoad가 제대로 작동합니다.
import javax.servlet.Filter;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
/**
* Register the {@link OpenEntityManagerInViewFilter} so that the
* GraphQL-Servlet can handle lazy loads during execution.
*
* @return
*/
@Bean
public Filter OpenFilter() {
return new OpenEntityManagerInViewFilter();
}
}
나는 그것을 해결했고 graphql-java-tools 라이브러리의 설명서를 더 주의 깊게 읽었어야 했다고 생각합니다. GraphQLQueryResolver
그것은 내가 또한 필요로 했던 기본적인 질문들을 해결합니다.GraphQLResolver<T>
나로서는Show
클래스, 다음과 같이 표시됩니다.
@Component
public class ShowResolver implements GraphQLResolver<Show> {
@Autowired
private CompetitionRepository competitionRepository;
public List<Competition> competitions(Show show) {
return ((List<Competition>)competitionRepository.findByShowId(show.getId()));
}
}
라이브러리에서 내부의 복잡한 개체를 해결하는 방법을 알려줍니다.Show
에서 " 클스이며, ▁the▁to▁include▁class▁requests다▁is▁the▁▁only▁and▁used 사용됩니다.Competition
복 많이 !새해 복 많이 받으세요.
EDIT 31.07.2019: 저는 그 이후 아래의 해결책에서 벗어났습니다.트랜잭션을 장시간 실행하는 것은 좋은 방법이 아니며, 이 경우 응용프로그램을 확장하면 문제가 발생할 수 있습니다.우리는 비동기식으로 쿼리를 일괄 처리하기 위해 DataLoader를 구현하기 시작했습니다.DataLoaders의 비동기성과 함께 장시간 실행되는 트랜잭션은 교착 상태를 초래할 수 있습니다. https://github.com/graphql-java-kickstart/graphql-java-tools/issues/58#issuecomment-398761715 (자세한 내용은 위와 아래).아래 솔루션은 배치된 쿼리가 필요 없는 소규모 응용프로그램 및/또는 응용프로그램에 여전히 좋은 출발점이 될 수 있으므로 제거하지는 않겠지만, 이 의견을 염두에 두십시오.
편집: 요청하신 대로 사용자 지정 실행 전략을 사용하는 다른 솔루션이 있습니다.사용 중graphql-spring-boot-starter
그리고.graphql-java-tools
:
의 콩 ExecutionStrategy
다음과 같이 트랜잭션을 처리합니다.
@Service(GraphQLWebAutoConfiguration.QUERY_EXECUTION_STRATEGY)
public class AsyncTransactionalExecutionStrategy extends AsyncExecutionStrategy {
@Override
@Transactional
public CompletableFuture<ExecutionResult> execute(ExecutionContext executionContext, ExecutionStrategyParameters parameters) throws NonNullableFieldWasNullException {
return super.execute(executionContext, parameters);
}
}
이렇게 하면 쿼리의 전체 실행이 동일한 트랜잭션 내에 배치됩니다.이것이 가장 최적의 해결책인지, 그리고 오류 처리와 관련하여 이미 몇 가지 단점이 있지만, 당신은 그런 식으로 유형 해결책을 정의할 필요가 없습니다.
이 유일한 것이라면 하세요.ExecutionStrategy
존재하는 콩, 이것은 콩 이름이 암시하는 것과는 반대로 돌연변이에도 사용될 것입니다.자세한 내용은 https://github.com/graphql-java-kickstart/graphql-spring-boot/blob/v11.1.0/graphql-spring-boot-autoconfigure/src/main/java/graphql/kickstart/spring/web/boot/GraphQLWebAutoConfiguration.java#L161-L166 을 참조하십시오.이를 방지하려면 다른 항목을 정의합니다.ExecutionStrategy
돌연변이에 사용:
@Bean(GraphQLWebAutoConfiguration.MUTATION_EXECUTION_STRATEGY)
public ExecutionStrategy queryExecutionStrategy() {
return new AsyncSerialExecutionStrategy();
}
수락된 답변에 대해 혼란스러운 사람은 양방향 관계를 포함하도록 Java 엔티티를 변경하고 도우미 방법을 사용하여 다음을 추가해야 합니다.Competition
그렇지 않으면 관계를 올바르게 설정하는 것을 잊기 쉽습니다.
@Entity
class Show {
private Long id;
private String name;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "show")
private List<Competition> competition;
public void addCompetition(Competition c) {
c.setShow(this);
competition.add(c);
}
}
@Entity
class Competition {
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
private Show show;
}
승인된 답변 뒤의 일반적인 직관은 다음과 같습니다.
graphql ShowResolver
그러면 프로그램 목록을 가져오기 위해 트랜잭션이 열리지만 해당 작업이 완료되면 트랜잭션이 닫힙니다.
그다음다음대중한첩음리쿼에다런ql▁graphql▁nested▁for리에 대한 중첩 쿼리competitions
를 호출하려고 .getCompetition()
각각의 Show
로, " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "LazyInitializationException
거래가 종료되었기 때문입니다.
{
shows {
id
name
competitions {
id
}
}
}
승인된 답변은 기본적으로 경기 목록을 검색하는 것을 우회하는 것입니다.OneToMany
문제를 제거하는 새 트랜잭션에 새 쿼리를 만듭니다.
이게 해킹인지는 모르겠지만,@Transactional
해결책에 대한 논리는 일리가 있지만 근본 원인을 확실히 이해하지 못합니다.
나를 위해 사용하는AsyncTransactionalExecutionStrategy
상태로 예: 게으른 이니시에이터 앱 수준 예외가 트랜잭션을 롤백 전용 상태로 트리거했습니다.은 전략의 .execute
,발생시키는HttpRequestHandlerImpl
400개의 빈 응답을 반환합니다.자세한 내용은 https://github.com/graphql-java-kickstart/graphql-java-servlet/issues/250 및 https://github.com/graphql-java/graphql-java/issues/1652 을 참조하십시오.
가 있었던 은 제게효있것은던을 사용한 입니다.Instrumentation
전체 작업을 트랜잭션으로 마무리하려면: https://graph.chat/graphql/일반/부분적으로 스프링 포함~47749680-3bb7-4508-8935-1d20d04d0c6a
당신이 쇼 개체를 가져올 때마다 쇼 개체의 모든 관련 경쟁을 원한다고 생각합니다.
기본적으로 엔티티의 모든 컬렉션 유형에 대한 가져오기 유형은 LAY입니다.최대 절전 모드가 컬렉션을 가져오도록 EARGER 유형을 지정할 수 있습니다.
Show 클래스에서 fetchType을 EAGER로 변경할 수 있습니다.
@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
private List<Competition> competition;
당신은 당신의 해결자 클래스에 주석을 달기만 하면 됩니다.@Transactional
그러면 저장소에서 반환된 엔티티는 데이터를 천천히 가져올 수 있습니다.
언급URL : https://stackoverflow.com/questions/48037601/lazyinitializationexception-with-graphql-spring
'programing' 카테고리의 다른 글
Excel의 문자열과 셀 내용 비교 (0) | 2023.07.15 |
---|---|
SonarQube SpringBoot 프로젝트의 "구성 가능한 이 응용프로그램 컨텍스트 닫기" (0) | 2023.07.15 |
C#에서 세션 변수가 null이거나 비어 있는지 확인하는 가장 좋은 방법은 무엇입니까? (0) | 2023.07.15 |
GitHub.com 에 대한 리포지토리 크기 제한 (0) | 2023.07.15 |
application.dev.properties 파일을 로드하지 않는 Springboot (0) | 2023.07.15 |