# JPA org.hibernate.LazyInitializationException / Spring @Transactional



## facefab (18. Okt 2016)

Hi, 
ich erhalte folgende Error-message (s.u.), wenn ich auf meine getChildren() Methode meiner TreeNode-Klasse zugreifen will. Hier der Code:


```
@Entity
@Transactional
public class TreeNode implements Serializable{

    @Id
    @GeneratedValue
    protected Long id;
    protected String name="";
   
    @ManyToOne
    protected Device device = null;
       
    @ManyToOne
    @JoinColumn(name="parent_id")
    protected TreeNode parent = null;
   
     @OneToMany(mappedBy="parent", fetch = FetchType.LAZY)
     protected Set<TreeNode> children = new HashSet<TreeNode>();
    
    
   
    protected TreeNode(){}
....

    @Transactional
   public Set<TreeNode> getChildren(){
     return this.children;
...
   }
```


```
@Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(securedEnabled = true)
    @EnableTransactionManagement
    public static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
   
   @Override
    protected void configure(HttpSecurity http) throws Exception {
       
     HttpSessionSecurityContextRepository securityContextRepository = new HttpSessionSecurityContextRepository();
         SecurityContextPersistenceFilter filter = new SecurityContextPersistenceFilter(securityContextRepository);

    http
    .csrf().disable() // Use Vaadin's CSRF protection
    .addFilter(filter);
    }

  
    }
```


Und hier die Exception:

```
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: x.z.y.data.TreeNode.children, could not initialize proxy - no Session
   at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:587) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
   at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:204) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
   at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:148) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
   at org.hibernate.collection.internal.PersistentSet.size(PersistentSet.java:143) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
   at x.y.z.data.TreeNode.getChildren(TreeNode.java:277) ~[classes/:na]
```

Weiss jemand woran das liegen könnte?


----------



## mrBrown (18. Okt 2016)

Du greifst außerhalb einer Transaktion auf `getChildren()` zu, das Set kann dann nicht mehr Lazy instanziiert werden. Fixen könnte man das mit FetchType Eager (allerdings hast du explizit Lazy gesetzt), vermutlich wäre es daher sinnvoller, deine Transaktionen passend zu setzten.

`@Transactional` an den Entitys hat nicht viel Sinn, das sollte ab die Services dran.


----------



## Steven Hachel (18. Okt 2016)

Wie mrBrown schon erwähnt hat, wird die Annotation @Transactional nicht in einer Entity verwendet, sondern gehört in den Service, der mit den Entitäten arbeitet...
Wie ich sehe, arbeitest du mit Hibernate, ohne einem Framework drum herum. Ich kann dir da nur EclipseLink ans Herz legen. Dieses unterstützt LAZY Loading. Mit plain Hibernate ist es etwas tricki. Schaue dir mal diesen etwas älteren Artikel hierzu an, damit du evtll. verstehst, was da im Hintergrund passiert.
http://www.empulse.de/2014/08/08/eclipselink-bessere-hibernate/

viel Spaß beim lesen
Steven


----------



## mrBrown (18. Okt 2016)

Steven Hachel hat gesagt.:


> Wie ich sehe, arbeitest du mit Hibernate, ohne einem Framework drum herum. Ich kann dir da nur EclipseLink ans Herz legen. Dieses unterstützt LAZY Loading. Mit plain Hibernate ist es etwas tricki. Schaue dir mal diesen etwas älteren Artikel hierzu an, damit du evtll. verstehst, was da im Hintergrund passiert.


Er arbeitet schon mit Spring, das dürfte noch weiter abstrahieren als EclipseLink. Direkt mit Hibernate kommt er da überhaupt nicht in Berührung (und Lazy Loading ist auch absolut kein Problem)


----------



## stg (19. Okt 2016)

mrBrown hat gesagt.:


> das Set kann dann nicht mehr Lazy instanziiert werden



"kann" ist nicht ganz richtig. Die JPA Spezifikation schreibt das Verhalten hier nicht explizit vor. EclipseLink bspw unterstützt unter gewissen Bedingungen LazyLoading auch außerhalb (bzw nach beenden) der Transaction. Nur als kleine Anmerkung.   Das Problem hast du natürlich richtig angemerkt, und EclipseLink nutzt er ja nunmal nicht. Und den Hinweis, statt Hibernate auf EclipseLink umzusteigen, finde ich genau wie du auch quatsch. DAS ist sicherlich kein Grund der dafür spricht..

Statt generell von Lazy auf Eager Loading zu wechseln ist es ggfls sinnvoller passende Fetch-Graphen zu definieren. Siehe z.B. hier: http://www.thoughts-on-java.org/jpa-21-entity-graph-part-1-named-entity/

Mit tiefen Baumstrukturen, die komplett geladen werden müssen, hab ich mit JPA aber eigentlich immer schlechte Erfahrungen gemacht, was die Performance angeht, da mir da immer zu viele aufeinanderfolgende Datenbankabfragen erzeugt wurden. Ich lade in vielen Fällen einfach die Informationen über die Relationen von Parents zu Childs aus passenden Join Tables manuell und setze die Relationen dann selbst. Ist relativ straight forward und geht mit nur 2-3 Datenbankabfragen und mit dem setzen der Relationen in linearer Zeit auch "rasend schnell".


----------



## facefab (19. Okt 2016)

Hi,
vielen Dank für die Hinweise. Ich werde mich da jetzt mal genauer mit der Lösung beschäftigen. Ich hatte bisher auch eine EAGER Strategie, aber beim DB-Update einzelner Nodes ging die Perfomance extrem in den Keller, was ich durch die LAZY-Strategie beheben wollte.


----------

