Spring Data JPA – “Proxy konnte nicht initialisiert werden – keine Sitzung” – Mit als transaktional markierten Methoden

Lesezeit: 7 Minuten

Benutzeravatar von douglasrlee
Douglasie

Ich habe ein Modell mit einem ziemlich großen Diagramm von Untereinheiten, und der Ruhezustand macht am Ende etwa 9 Anweisungen, um alle erforderlichen Daten faul abzurufen, aber etwa 4 Ebenen tief erhalte ich den Fehler “Proxy konnte nicht initialisiert werden – keine Sitzung” und ich bin es nicht sicher warum.

Regler

@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;
}

Moderator

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());
  }
}

Planen

@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;
  }
}

Plandetail

@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;
}

Broschüre Abschnitt

@Entity
public class BrochureSection implements Serializable {
  private static final long serialVersionUID = 1856191232387921427L;

  (Column definitions)
}

Ausnahme

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/:?]

Jede Hilfe wäre willkommen.

  • Der Frieden des Codes würde helfen. Einfacher Ansatz, der Ihnen helfen würde, das VO-Objekt vom Dienst zurückzugeben oder den FetchType zu ändern.

    – AntonN

    12. April 2016 um 20:26 Uhr

  • Wenn ich also den Abruftyp in EAGER ändere, kann ich es zum Laufen bringen, ABER ich möchte es aus Leistungsgründen nicht wirklich.

    – Douglasie

    12. April 2016 um 20:44 Uhr

  • Gemäß dem Fehler und dem Code, wenn der Broschürenabschnitt fehlschlägt. Können Sie hibernate.instance(this.plandetail.getbrochure()) in Ihrer getdescription()-Methode hinzufügen. Da dieses Attribut verzögert geladen wird, kann Ihr Code in get description es nicht finden. Um es zu verwenden, müssen Sie es zuerst laden und tun, was Sie damit tun möchten. Bitte lassen Sie mich wissen, ob dies hilft. Nur um darauf hinzuweisen, dass ich auch neu im Ruhezustand bin und diesen Fehler persönlich festgestellt habe und auf diese Weise beheben konnte

    – Lernphase

    12. April 2016 um 21:29 Uhr


  • Wie erhalte ich die Hibernate-Variable in diesem Modell?

    – Douglasie

    12. April 2016 um 21:31 Uhr

  • Schnelle Lösung: myEntity.getListOfThings().size(); Zwingen Sie JPA, die Sammlung zu initialisieren.

    – AntonN

    13. April 2016 um 11:56 Uhr

Wenn Sie es behalten möchten Lazy-Load und Sie Spring Boot verwenden, fügen Sie einfach die folgende Konfiguration in Ihre hinzu application.properties:

spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

  • Nur weil ich neugierig bin. Wo hast du das gefunden?

    – Douglasie

    30. August 2016 um 19:14 Uhr

  • Eigentlich ist es ein Anti-Pattern, für weitere Erklärungen schauen Sie bitte unter vladmihalcea.com/2016/09/05/…

    – verdunkelt

    2. Mai 2017 um 13:50 Uhr

  • @Jules stimmte zu, nicht alle Anwendungen benötigen die höchste Leistung, aber es ist ein Beispiel für eine Lösung, die normalerweise ineffektiv ist und das Risiko eingeht, höchst kontraproduktiv zu sein (was die Definition der Anti-Patterns auf Wikipedia ist en.wikipedia.org/wiki/Anti-Pattern).

    – verdunkelt

    7. August 2017 um 13:22 Uhr

  • Gibt es sicher eine andere Möglichkeit, das Problem zu beheben? vielleicht direkt in jpql die abfrage schreiben?

    – Robert Trudel

    18. Oktober 2017 um 20:52 Uhr

  • Dies sind interessante Informationen, aber die Frage ist eher, warum “@Transactional” nicht ausreicht, um die Transaktion imo offen zu halten.

    – Tristan

    2. Juli 2018 um 15:27 Uhr

Das verzögerte Laden kann beibehalten werden, ohne den Parameter enable_lazy_load_no_trans zu setzen. Die einfachste Lösung, die ich gefunden habe, war @NamedEntityGraph bei der Verwendung von Spring Data JPA. https://www.baeldung.com/spring-data-jpa-named-entity-graphs

Der Nachteil war, dass ich nicht mehr als eine Sammlung im @NamedEntityGraph haben konnte. Das Hinzufügen einer zweiten Sammlung führte zu einer Ausnahme org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags:

Wenn Sie das Antimuster also nicht verwenden möchten und nur eine Sammlung zu laden versuchen, funktionieren @NamedEntityGraph und @EntityGrpah mit Spring Data JPA.

  • Nun, Sie können die multipleBagException tatsächlich vermeiden, indem Sie Sets anstelle von Sammlungen oder Listen verwenden …

    – Benutzer1006641

    26. November 2020 um 13:47 Uhr

  • Die Verwendung von Mengen anstelle von Listen ist laut eine schlechte Idee vladmihalcea.com/hibernate-multiplebagfetchexception

    – Wim Deblauwe

    22. Oktober 2021 um 9:45 Uhr

Benutzeravatar von Chaman Jain
Chaman Jain

Hinzufügen @Transactional over-Methode funktioniert für mich

Ich hatte die gleiche Ausnahme und das Problem war, dass ich eine Entität hatte, bei der die Zuordnung fehlte

@Entity
Class A {
}

@Entity
Class B {

   private A a;
}

Lösung

@Entity
Class B {

  @OneToOne
  @MapsId
  private A a;
}

spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true Es ist ein Anti-Pattern und es wird dringend empfohlen, es nicht zu verwenden.

could not initialize proxy Eine Ausnahme tritt häufig auf, wenn eine untergeordnete Klasse enthält
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) in deiner Beziehung.

Ich empfehle zu verwenden fetch = FetchType.EAGER in Ihrer Beziehung statt zu konsumieren LAZY. Es ist nicht der beste Weg, aber es ist viel besser als die Verwendung von Anti-Pattern.

  • FetchType.EAGER hat bei mir funktioniert. Ich denke, Ihre Antwort sollte mehr Stimmen erhalten, es ist einfach, über Antimuster zu sprechen, aber Sie haben tatsächlich eine Alternative bereitgestellt, danke!

    – chriszichrisz

    29. Juni 2022 um 21:07 Uhr

  • FetchType.EAGER hat bei mir funktioniert. Ich denke, Ihre Antwort sollte mehr Stimmen erhalten, es ist einfach, über Antimuster zu sprechen, aber Sie haben tatsächlich eine Alternative bereitgestellt, danke!

    – chriszichrisz

    29. Juni 2022 um 21:07 Uhr

1444310cookie-checkSpring Data JPA – “Proxy konnte nicht initialisiert werden – keine Sitzung” – Mit als transaktional markierten Methoden

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy