hibernate Spring Data JPA -“could not initialize proxy - no Session”- With Methods marked as transactional

svmlkihl  于 2023-10-23  发布在  Spring
关注(0)|答案(6)|浏览(151)

我有一个模型,它有一个相当大的子实体图,hibernate最终做了大约9个语句来懒惰地获取所有需要的数据,但大约4个级别深,我得到了一个“无法初始化代理-没有会话”错误,我不知道为什么。
控制器

  1. @Transactional(readOnly = true)
  2. @RequestMapping(value = "/v2/plans", method = RequestMethod.GET)
  3. public @ResponseBody List<PlanPresenter> show(HttpServletRequest request) throws Exception {
  4. List<PlanPresenter> planPresenters = new ArrayList<>();
  5. CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
  6. CriteriaQuery<Plan> planQuery = criteriaBuilder.createQuery(Plan.class);
  7. Root<Plan> root = planQuery.from(Plan.class);
  8. if (request.getParameter("region") != null || request.getParameter("group") != null) {
  9. List<Predicate> criteria = new ArrayList<Predicate>();
  10. if (request.getParameter("region") != null) {
  11. criteria.add(criteriaBuilder.equal(root.get(Plan_.region), request.getParameter("region")));
  12. }
  13. if (request.getParameter("group") != null) {
  14. criteria.add(criteriaBuilder.equal(root.get(Plan_.groupCode), request.getParameter("group")));
  15. criteria.add(root.get(Plan_.planSetId).in(groupPlanSetIds));
  16. } else {
  17. criteria.add(root.get(Plan_.planSetId).in(currentPlanSetIds));
  18. }
  19. Query query = entityManager.createQuery(planQuery.where(criteriaBuilder.and(criteria.toArray(new Predicate[]{}))));
  20. for (Plan plan : (List<Plan>)query.getResultList()) {
  21. planPresenters.add(new PlanPresenter(plan));
  22. }
  23. }
  24. return planPresenters;
  25. }

主持人

  1. public class PlanPresenter {
  2. public String id;
  3. public String plan_set_id;
  4. public String region;
  5. public String name;
  6. public String description;
  7. public HashMap<String, Object> details = new HashMap<String, Object>();
  8. public PlanPresenter(Plan plan) throws Exception {
  9. this.id = String.valueOf(plan.id);
  10. this.plan_set_id = String.valueOf(plan.planSetId);
  11. this.region = plan.region.trim();
  12. this.name = plan.getName();
  13. this.description = plan.getDescription();
  14. this.details.put("spanish_plan", plan.isSpanishPlan());
  15. this.details.put("mutually_exclusive", plan.isMutuallyExclusive());
  16. this.details.put("group_plan", plan.isGroupPlan());
  17. this.details.put("group_code", plan.groupCode.trim());
  18. this.details.put("family_plan", plan.isFamilyPlan());
  19. this.details.put("price", plan.getPrice());
  20. this.details.put("enrollment_fee", plan.getEnrollmentFee());
  21. this.details.put("riders", plan.getRiders());
  22. }
  23. }

计划

  1. @Entity
  2. public class Plan implements Serializable {
  3. private static final long serialVersionUID = 7639611964474770505L;
  4. private static List<String> familyPlanShortNames = Arrays.asList("ABCD");
  5. @Transient
  6. private String description = "";
  7. (Column definitions)
  8. @ManyToOne(fetch = FetchType.LAZY)
  9. @JoinColumn(name = "XXXX", insertable = false, updatable = false, nullable = true)
  10. @NotFound(action = NotFoundAction.IGNORE)
  11. public PlanDetail planDetail;
  12. @OneToMany(fetch = FetchType.LAZY)
  13. @JoinColumn(name = "XXXX", insertable = false, updatable = false, nullable = true)
  14. @OrderBy("XXXX")
  15. @NotFound(action = NotFoundAction.IGNORE)
  16. public List<Rider> riders;
  17. public String getName() {
  18. return this.planDetail != null ? this.planDetail.longName.trim() : null;
  19. }
  20. public Boolean isSpanishPlan() {
  21. return this.language.trim().equals("ES");
  22. }
  23. public Boolean isMutuallyExclusive() {
  24. return this.mutuallyExclusive.trim().equals("Y");
  25. }
  26. public Boolean isGroupPlan() {
  27. return this.groupCode != null && !this.groupCode.trim().equals("");
  28. }
  29. public Boolean isFamilyPlan() {
  30. return familyPlanShortNames.contains(this.planDetail.shortName.trim());
  31. }
  32. public BigDecimal getPrice() {
  33. return this.planDetail != null ? this.planDetail.price.setScale(2) : null;
  34. }
  35. public BigDecimal getEnrollmentFee() {
  36. return this.planDetail != null ? this.planDetail.enrollmentFee.setScale(2) : null;
  37. }
  38. public String getDescription() {
  39. if (this.planDetail != null && this.planDetail.brochureSections != null) {
  40. this.planDetail.brochureSections.forEach((brochureSection) -> {
  41. if (brochureSection.type.trim().equals("P1") && brochureSection.order == 1) {
  42. this.description = this.description + " " + brochureSection.text.trim();
  43. }
  44. });
  45. }
  46. return this.description.trim();
  47. }
  48. public List<HashMap<String, Object>> getRiders() {
  49. List<HashMap<String, Object>> riders = new ArrayList<HashMap<String, Object>>();
  50. if (this.riders != null && this.riders.size() > 0) {
  51. this.riders.forEach((rider) -> {
  52. HashMap<String, Object> planRider = new HashMap<String, Object>();
  53. planRider.put("name", rider.getName());
  54. planRider.put("price", rider.getPrice());
  55. planRider.put("description", rider.getDescription());
  56. riders.add(planRider);
  57. });
  58. }
  59. return riders;
  60. }
  61. }

计划细节

  1. @Entity
  2. public class PlanDetail implements Serializable {
  3. private static final long serialVersionUID = 2256881691562712018L;
  4. (Column definitions)
  5. @OneToMany(fetch = FetchType.LAZY)
  6. @JoinColumn(name = "XXXX", referencedColumnName = "XXXX", insertable = false, updatable = false, nullable = true)
  7. @OrderBy("XXXX")
  8. @NotFound(action = NotFoundAction.IGNORE)
  9. public List<BrochureSection> brochureSections;
  10. }

宣传册部分

  1. @Entity
  2. public class BrochureSection implements Serializable {
  3. private static final long serialVersionUID = 1856191232387921427L;
  4. (Column definitions)
  5. }

例外

  1. org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.models.PlanDetail.brochureSections, could not initialize proxy - no Session
  2. at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:576) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
  3. at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:215) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
  4. at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:555) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
  5. at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:143) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
  6. at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:294) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
  7. at java.lang.Iterable.forEach(Iterable.java:74) ~[?:1.8.0_66]
  8. at com.models.Plan.getDescription(Plan.java:100) ~[classes/:?]
  9. at com.presenters.v2.PlanPresenter.<init>(PlanPresenter.java:20) ~[classes/:?]
  10. at com.controllers.v2.PlansController.show(PlansController.java:64) ~[classes/:?]

如果你能帮忙的话,我将不胜感激。

a6b3iqyw

a6b3iqyw1#

如果您想保留Lazy Load,并且您使用的是Sping Boot ,只需在您的application.properties中添加以下配置即可:

  1. spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
carvr3hs

carvr3hs2#

延迟加载可以保持,而无需设置enable_lazy_load_no_transs参数。我发现的最简单的解决方案是在使用Spring Data JPA时使用@ NamedLogistyGraph。https://www.baeldung.com/spring-data-jpa-named-entity-graphs
缺点是我不能在@ NamedLogistyGraph中拥有多个集合。添加第二个集合导致异常org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags:
因此,如果您不想使用反模式,并且只有一个集合要加载,则@ NamedNottyGraph和@ NottyGrpah与Spring Data JPA一起使用。

bwleehnv

bwleehnv3#

在方法上添加@Transactional对我来说很有效

ui7jx7zq

ui7jx7zq4#

spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true这是一个反模式,强烈建议避免使用它。
could not initialize proxy异常会经常发生,当子类在你的关系中包含@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})时。
我建议在你的关系中使用fetch = FetchType.EAGER而不是使用LAZY。这不是最好的方法,但比使用反模式要好得多。

nwsw7zdq

nwsw7zdq5#

在我的例子中,我有一个类,有几个ManyToOne和ManyToMany关系。因此,需要从数据库中加载几个对象列表。我通过将这些对象转换为DTO解决了这个问题。与传递可能链接到其他对象的对象列表不同,您传递的是只包含原语和字符串的DTO列表。这是一个巨大的性能提升器

8wigbo56

8wigbo566#

只需在服务中的方法上方添加@Transactional,并确保从SpringBoot而不是从jakboot导入使用transmitting

相关问题