Jeong SangCheol
Jeong SangCheol

Reputation: 113

hibernate : org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: no session or session was closed

I'm learn to hibernate. But I'm stuck in a very basic point.

When the source of the following

    Controller : data collection and ready to display 
    Service : Transaction processing
    Dao : access Database 

And processing data in such a form.


Test.java

@Entity
@Table ( name = "table_test" )
public class Test
{

    @Id
    @GeneratedValue ( strategy = GenerationType.AUTO )
    public long id;

    @OneToMany(fetch=FetchType.LAZY)
    @JoinColumn(name="test_id")
    @IndexColumn(name="orderBy")
    public List<TestItem> items;

}

TestItem.java

@Entity
@Table ( name = "table_item" )
public class TestItem
{

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="test_id", insertable=false, updatable=false)
    public Test parent;

    @Id
    @GeneratedValue ( strategy = GenerationType.AUTO )
    public long id;

}

TestDao.java

@Repository
public class TestDao
{

    @Autowired SessionFactory sessionFactory;

    protected Session getSession(){
        return sessionFactory.getCurrentSession();
    }

    public Test get(long id){
        return (Test) getSession().createCriteria( Test.class )
                    .add( Restrictions.eq( "id", id ) ).uniqueResult();
    }
}

TestService.java

@Service
@Transactional
public class TestService
{

    @Autowired
    TestDao testd;

    public Test get(long id){
        return testd.get( id );
    }

    public List<TestItem> getItems(Test test){
        List<TestItem> items = test.items;
        items.iterator();
        return items;
    }

}

TestController.java

@Controller
@RequestMapping ( "/test" )
public class TestController extends BaseController
{
    @Autowired
    TestService testService;

    @RequestMapping ( "/{id}" )
    public String seriesList ( @PathVariable long id, Model model )
    {
        Test test = testService.get( id );

        //something...

        List<TestItem> lists = testService.getItems( test );

        for(TestItem item : lists)
        {
            Model.addAttribute(item.id);
        }

        return "index";
    }
}

EXCEPTION

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.test.domain.Test.items, no session or session was closed
    org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383)
    org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375)
    org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:368)

For what reason if I use the Lazy.

This is because it may not be used by the "Something" that list.

I know how to work around some.

1) first solution is "already list", but eliminates the need for the lazy.

@Service
@Transactional
public class TestService
{

    @Autowired
    TestDao testd;

    public Test get(long id){
        Test test = testd.get( id );
        test.items.iterator();
        return test;
    }

    public List<TestItem> getItems(Test test){
        List<TestItem> items = test.items;
        items.iterator();
        return items;
    }

}

2) second solution "process by inner Transaction", but this solution use, always run in transaction

@Controller
@RequestMapping ( "/test" )
public class TestController extends BaseController
{
    @Autowired
    TestService testService;

    @RequestMapping ( "/{id}" )
    public String seriesList ( @PathVariable long id, Model model )
    {
        return testService.view( id, model );
    }
}
@Service
@Transactional
public class TestService
{

    @Autowired
    TestDao testd;

    public Test get(long id){
        Test test = testd.get( id );
        return test;
    }

    public String view(long id, Model model){
        Test test = get( id );

        List<TestItem> lists = test.items;

        for(TestItem item : lists)
        {
            model.addAttribute( item.id );
        }

        return "index";
    }

}

There seems to have several problems.

So, I want to bring up only when needed.

Upvotes: 4

Views: 1157

Answers (1)

lalit
lalit

Reputation: 1475

You will need to understand the concept of Session and session boundaries. Hibernate works with proxies for reason of performance and does not loads all the associations unless they are needed. For Session concepts you can see here

If you are in Spring environment (which I think you are), you might want to check Open Session filter. This opens a session in the context of a request so that you can access associations in all layers. You might not want to increase your transaction boundaries.

Upvotes: 1

Related Questions