Hibernate/Spring: failed to lazily initialize - no session or session was closed
- by Niko
I know something similar has been asked already, but unfortunately I wasn't able to find a reliable answer - even with searching for over 2 days.
The basic problem is the same as asked multiple time. I have a simple program with two POJOs Event and User - where a user can have multiple events.
@Entity
@Table
public class Event {
    private Long id;
    private String name;
    private User user;
    @Column
    @Id
    @GeneratedValue
    public Long getId() {return id;}
    public void setId(Long id) { this.id = id;  }
    @Column
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    @ManyToOne
    @JoinColumn(name="user_id")
    public User getUser() {return user;}
    public void setUser(User user) {this.user = user;}
}
@Entity
@Table
public class User {
    private Long id;
    private String name;
    private List events;
    @Column
    @Id
    @GeneratedValue
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    @Column
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    @OneToMany(mappedBy="user", fetch=FetchType.LAZY)
    public List getEvents() { return events; }
    public void setEvents(List events) { this.events = events; }
}
Note: This is a sample project. I really want to use Lazy fetching here.
I use spring and hibernate and have a simple basic-db.xml for loading:
<?xml version="1.0" encoding="UTF-8"?
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
    <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close"  scope="thread"
        <property name="driverClassName" value="com.mysql.jdbc.Driver" /
        <property name="url" value="jdbc:mysql://192.168.1.34:3306/hibernateTest" /
        <property name="username" value="root" /
        <property name="password" value="" /
        <aop:scoped-proxy/
    </bean
    <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"
        <property name="scopes"
            <map
                <entry key="thread"
                    <bean class="org.springframework.context.support.SimpleThreadScope" /
                </entry
            </map
        </property
    </bean
    <bean id="mySessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" scope="thread"
        <property name="dataSource" ref="myDataSource" /
        <property name="annotatedClasses"
            <list
                <valuedata.model.User</value
                <valuedata.model.Event</value
            </list
        </property
        <property name="hibernateProperties"
            <props
                <prop key="hibernate.dialect"org.hibernate.dialect.MySQLDialect</prop
                <prop key="hibernate.show_sql"true</prop
                <prop key="hibernate.hbm2ddl.auto"create</prop
            </props
        </property
        <aop:scoped-proxy/
    </bean
    <bean id="myUserDAO" class="data.dao.impl.UserDaoImpl"
        <property name="sessionFactory" ref="mySessionFactory" /
    </bean
    <bean id="myEventDAO" class="data.dao.impl.EventDaoImpl"
        <property name="sessionFactory" ref="mySessionFactory" /
    </bean
</beans
Note: I played around with the CustomScopeConfigurer and SimpleThreadScope, but that didnt change anything.
I have a simple dao-impl (only pasting the userDao - the EventDao is pretty much the same - except with out the "listWith" function:
public class UserDaoImpl implements UserDao{
    private HibernateTemplate hibernateTemplate;
    public void  setSessionFactory(SessionFactory sessionFactory) {
        this.hibernateTemplate = new HibernateTemplate(sessionFactory);
    }
    @SuppressWarnings("unchecked")
    @Override
    public List listUser() {
        return hibernateTemplate.find("from User");
    }
    @Override
    public void saveUser(User user) {
        hibernateTemplate.saveOrUpdate(user);
    }
    @Override
    public List listUserWithEvent() {
        List users = hibernateTemplate.find("from User");
        for (User user : users) {
            System.out.println("LIST : " + user.getName() + ":");
            user.getEvents().size();
        }
        return users;
    }
}
I am getting the org.hibernate.LazyInitializationException - failed to lazily initialize a collection of role: data.model.User.events, no session or session was closed at the line with user.getEvents().size();
And last but not least here is the Test class I use:
public class HibernateTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("basic-db.xml");
        UserDao udao = (UserDao) ac.getBean("myUserDAO");
        EventDao edao = (EventDao) ac.getBean("myEventDAO");
        System.out.println("New user...");
        User user = new User();
        user.setName("test");
        Event event1 = new Event();
        event1.setName("Birthday1");
        event1.setUser(user);
        Event event2 = new Event();
        event2.setName("Birthday2");
        event2.setUser(user);
        udao.saveUser(user);
        edao.saveEvent(event1);
        edao.saveEvent(event2);
        List users = udao.listUserWithEvent();
        System.out.println("Events for users");
        for (User u : users) {
            System.out.println(u.getId() + ":" + u.getName() + " --");
            for (Event e : u.getEvents())
            {
                System.out.println("\t" + e.getId() + ":" + e.getName());
            }
        }
        ((ConfigurableApplicationContext)ac).close();
    }
}
and here is the Exception I get:
1621 [main] ERROR org.hibernate.LazyInitializationException - failed to lazily initialize a collection of role: data.model.User.events, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: data.model.User.events, no session or session was closed
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372)
    at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:119)
    at org.hibernate.collection.PersistentBag.size(PersistentBag.java:248)
    at data.dao.impl.UserDaoImpl.listUserWithEvent(UserDaoImpl.java:38)
    at HibernateTest.main(HibernateTest.java:44)
Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: data.model.User.events, no session or session was closed
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372)
    at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:119)
    at org.hibernate.collection.PersistentBag.size(PersistentBag.java:248)
    at data.dao.impl.UserDaoImpl.listUserWithEvent(UserDaoImpl.java:38)
    at HibernateTest.main(HibernateTest.java:44)
Things I tried but did not work:
assign a threadScope and using beanfactory (I used "request" or "thread" - no difference noticed):
        // scope stuff
        Scope threadScope = new SimpleThreadScope();
        ConfigurableListableBeanFactory beanFactory = ac.getBeanFactory();
        beanFactory.registerScope("request", threadScope);
        ac.refresh();
...
Setting up a transaction by getting the session object from the deo:
...
        Transaction tx = ((UserDaoImpl)udao).getSession().beginTransaction();
        tx.begin();
        users = udao.listUserWithEvent();
...
getting a transaction within the listUserWithEvent()
    public List listUserWithEvent() {
        SessionFactory sf = hibernateTemplate.getSessionFactory();
        Session s = sf.openSession();
        Transaction tx = s.beginTransaction();
        tx.begin();
        List users = hibernateTemplate.find("from User");
        for (User user : users) {
            System.out.println("LIST : " + user.getName() + ":");
            user.getEvents().size();
        }
        tx.commit();
        return users;
    }
I am really out of ideas by now. Also, using the listUser or listEvent just work fine.