Spring Data JPA - "프록시를 초기화할 수 없습니다 - 세션 없음" - 트랜잭션으로 표시된 메서드
서브 엔티티의 그래프가 매우 크고, 휴지 상태가 되어, 필요한 모든 데이터를 느릿느릿 취득하기 위한 스테이트먼트가 9개 정도 되는 모델이 있습니다만, 약 4레벨의 「cannot initialize proxy - no Session」에러가 발생하는데, 그 이유는 알 수 없습니다.
컨트롤러
@Transactional(readOnly = true)
@RequestMapping(value = "/v2/plans", method = RequestMethod.GET)
public @ResponseBody List<PlanPresenter> show(HttpServletRequest request) throws Exception {
List<PlanPresenter> planPresenters = new ArrayList<>();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Plan> planQuery = criteriaBuilder.createQuery(Plan.class);
Root<Plan> root = planQuery.from(Plan.class);
if (request.getParameter("region") != null || request.getParameter("group") != null) {
List<Predicate> criteria = new ArrayList<Predicate>();
if (request.getParameter("region") != null) {
criteria.add(criteriaBuilder.equal(root.get(Plan_.region), request.getParameter("region")));
}
if (request.getParameter("group") != null) {
criteria.add(criteriaBuilder.equal(root.get(Plan_.groupCode), request.getParameter("group")));
criteria.add(root.get(Plan_.planSetId).in(groupPlanSetIds));
} else {
criteria.add(root.get(Plan_.planSetId).in(currentPlanSetIds));
}
Query query = entityManager.createQuery(planQuery.where(criteriaBuilder.and(criteria.toArray(new Predicate[]{}))));
for (Plan plan : (List<Plan>)query.getResultList()) {
planPresenters.add(new PlanPresenter(plan));
}
}
return planPresenters;
}
발표자
public class PlanPresenter {
public String id;
public String plan_set_id;
public String region;
public String name;
public String description;
public HashMap<String, Object> details = new HashMap<String, Object>();
public PlanPresenter(Plan plan) throws Exception {
this.id = String.valueOf(plan.id);
this.plan_set_id = String.valueOf(plan.planSetId);
this.region = plan.region.trim();
this.name = plan.getName();
this.description = plan.getDescription();
this.details.put("spanish_plan", plan.isSpanishPlan());
this.details.put("mutually_exclusive", plan.isMutuallyExclusive());
this.details.put("group_plan", plan.isGroupPlan());
this.details.put("group_code", plan.groupCode.trim());
this.details.put("family_plan", plan.isFamilyPlan());
this.details.put("price", plan.getPrice());
this.details.put("enrollment_fee", plan.getEnrollmentFee());
this.details.put("riders", plan.getRiders());
}
}
계획
@Entity
public class Plan implements Serializable {
private static final long serialVersionUID = 7639611964474770505L;
private static List<String> familyPlanShortNames = Arrays.asList("ABCD");
@Transient
private String description = "";
(Column definitions)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "XXXX", insertable = false, updatable = false, nullable = true)
@NotFound(action = NotFoundAction.IGNORE)
public PlanDetail planDetail;
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "XXXX", insertable = false, updatable = false, nullable = true)
@OrderBy("XXXX")
@NotFound(action = NotFoundAction.IGNORE)
public List<Rider> riders;
public String getName() {
return this.planDetail != null ? this.planDetail.longName.trim() : null;
}
public Boolean isSpanishPlan() {
return this.language.trim().equals("ES");
}
public Boolean isMutuallyExclusive() {
return this.mutuallyExclusive.trim().equals("Y");
}
public Boolean isGroupPlan() {
return this.groupCode != null && !this.groupCode.trim().equals("");
}
public Boolean isFamilyPlan() {
return familyPlanShortNames.contains(this.planDetail.shortName.trim());
}
public BigDecimal getPrice() {
return this.planDetail != null ? this.planDetail.price.setScale(2) : null;
}
public BigDecimal getEnrollmentFee() {
return this.planDetail != null ? this.planDetail.enrollmentFee.setScale(2) : null;
}
public String getDescription() {
if (this.planDetail != null && this.planDetail.brochureSections != null) {
this.planDetail.brochureSections.forEach((brochureSection) -> {
if (brochureSection.type.trim().equals("P1") && brochureSection.order == 1) {
this.description = this.description + " " + brochureSection.text.trim();
}
});
}
return this.description.trim();
}
public List<HashMap<String, Object>> getRiders() {
List<HashMap<String, Object>> riders = new ArrayList<HashMap<String, Object>>();
if (this.riders != null && this.riders.size() > 0) {
this.riders.forEach((rider) -> {
HashMap<String, Object> planRider = new HashMap<String, Object>();
planRider.put("name", rider.getName());
planRider.put("price", rider.getPrice());
planRider.put("description", rider.getDescription());
riders.add(planRider);
});
}
return riders;
}
}
계획의 상세
@Entity
public class PlanDetail implements Serializable {
private static final long serialVersionUID = 2256881691562712018L;
(Column definitions)
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "XXXX", referencedColumnName = "XXXX", insertable = false, updatable = false, nullable = true)
@OrderBy("XXXX")
@NotFound(action = NotFoundAction.IGNORE)
public List<BrochureSection> brochureSections;
}
팜플렛 섹션
@Entity
public class BrochureSection implements Serializable {
private static final long serialVersionUID = 1856191232387921427L;
(Column definitions)
}
예외.
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.models.PlanDetail.brochureSections, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:576) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:215) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:555) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:143) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:294) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at java.lang.Iterable.forEach(Iterable.java:74) ~[?:1.8.0_66]
at com.models.Plan.getDescription(Plan.java:100) ~[classes/:?]
at com.presenters.v2.PlanPresenter.<init>(PlanPresenter.java:20) ~[classes/:?]
at com.controllers.v2.PlansController.show(PlansController.java:64) ~[classes/:?]
어떤 도움이라도 주시면 감사하겠습니다.
Lazy Load를 유지하고 스프링 부트를 사용하는 경우 application.properties에 다음 설정을 추가합니다.
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
느린 로드는 enable_lazy_load_no_trans 파라미터를 설정하지 않고 유지할 수 있습니다.제가 찾은 솔루션 중 가장 간단한 것은 Spring Data JPA를 사용하는 @NamedEntityGraph입니다.https://www.baeldung.com/spring-data-jpa-named-entity-graphs
단점은 @NamedEntityGraph에서 여러 컬렉션을 가질 수 없다는 것입니다.두 번째 컬렉션을 추가하면 예외가 발생했습니다.org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags:
따라서 안티패턴을 사용하지 않고 로드하려는 컬렉션이1개밖에 없는 경우 @NamedEntityGraph 및 @EntityGrpah는 Spring Data JPA와 함께 동작합니다.
추가 중@Transactional
오버메서드는 나에게 효과가 있다.
저도 같은 예외가 있었는데 문제는 매핑을 놓친 엔티티가 있다는 거예요.
@Entity
Class A {
}
@Entity
Class B {
private A a;
}
솔루션
@Entity
Class B {
@OneToOne
@MapsId
private A a;
}
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
안티패턴이므로 사용을 피하는 것이 좋습니다.
could not initialize proxy
예외는 종종 자식 클래스가 다음을 포함할 때 발생합니다.@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
두 분의 관계에서요.
사용하는 것을 추천합니다.fetch = FetchType.EAGER
당신과의 관계에서LAZY
최선의 방법은 아니지만 안티패턴을 사용하는 것보다 훨씬 낫다.
언급URL : https://stackoverflow.com/questions/36583185/spring-data-jpa-could-not-initialize-proxy-no-session-with-methods-marke
'code' 카테고리의 다른 글
WordPress 데이터 모듈 선택기에서 오류 처리 (0) | 2023.02.22 |
---|---|
Mongoose Unique 인덱스가 작동하지 않습니다! (0) | 2023.02.22 |
모든 소품을 useCallback과 useMemo 중 어느 것으로 랩해야 합니까?이 후크를 사용할 때는? (0) | 2023.02.22 |
네이티브: require()를 다이내믹 문자열로 리액트하시겠습니까? (0) | 2023.02.22 |
이온으로 표 작성 (0) | 2023.02.22 |