Hibernate/Spring: failed to lazily initialize - no session or session was closed Hibernate/Spring: failed to lazily initialize - no session or session was closed java java

Hibernate/Spring: failed to lazily initialize - no session or session was closed


I think you should not use the hibernate session transactional methods, but let spring do that.

Add this to your spring conf:

<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">    <property name="sessionFactory" ref="mySessionFactory" /></bean><bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">    <property name="transactionManager" ref="txManager"/></bean>

and then I would modify your test method to use the spring transaction template:

public static void main(String[] args) {    // init here (getting dao and transaction template)    transactionTemplate.execute(new TransactionCallback() {        @Override        public Object doInTransaction(TransactionStatus status) {          // do your hibernate stuff in here : call save, list method, etc        }    }}

as a side note, @OneToMany associations are lazy by default, so you don't need to annotate it lazy. (@*ToMany are LAZY by default, @*ToOne are EAGER by default)

EDIT: here is now what is happening from hibernate point of view:

  • open session (with transaction start)
  • save a user and keep it in the session (see the session cache as an entity hashmap where the key is the entity id)
  • save an event and keep it in the session
  • save another event and keep it in the session
  • ... same with all the save operations ...

  • then load all users (the "from Users" query)

  • at that point hibernate see that it has already the object in its session, so discard the one it got from the request and return the one from the session.
  • your user in the session does not have its event collection initialized, so you get null.
  • ...

Here are some points to enhance your code:

  • in your model, when collection ordering is not needed, use Set, not List for your collections (private Set events, not private List events)
  • in your model, type your collections, otherwise hibernate won't which entity to fetch (private Set<Event> events)
  • when you set one side of a bidirectional relation, and you wish to use the mappedBy side of the relation in the same transaction, set both sides. Hibernate will not do it for you before the next tx (when the session is a fresh view from the db state).

So to address the point above, either do the save in one transaction, and the loading in another one :

public static void main(String[] args) {    // init here (getting dao and transaction template)    transactionTemplate.execute(new TransactionCallback() {        @Override        public Object doInTransaction(TransactionStatus status) {          // save here        }    }    transactionTemplate.execute(new TransactionCallback() {        @Override        public Object doInTransaction(TransactionStatus status) {          // list here        }    }}

or set both sides:

...event1.setUser(user);...event2.setUser(user);...user.setEvents(Arrays.asList(event1,event2));...

(Also do not forget to address the code enhancement points above, Set not List, collection typing)


In case of Web application, it is also possible to declare a special Filter in web.xml, that will do session-per-request:

<filter>    <filter-name>openSessionInViewFilter</filter-name>    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class></filter><filter-mapping>    <filter-name>openSessionInViewFilter</filter-name>    <url-pattern>/*</url-pattern></filter-mapping>

After that you can lazyload your data anytime during the request.


I got here looking for a hint regarding a similar problem. I tried the solution mentioned by Thierry and it didnt work. After that I tried these lines and it worked:

SessionFactory sessionFactory = (SessionFactory) context.getBean("sessionFactory");Session session = SessionFactoryUtils.getSession(sessionFactory, true);TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));

Indeed what I'm doing is a batch process that must leverage Spring existings managers/services. After loading the context and doing some invocations I founded the famous issue "failed to lazily initialize a collection". Those 3 lines solved it for me.