hibernate 懒加载异常分析: failed to lazily initialize a collection of role

时间:2022-12-21 17:29:32

初始环境:hibernate 每个用户对应一个小组 。user--group(many to one)。group--user(one to many)  


Group代码片段

@OneToMany(mappedBy="group" )
@JoinColumn(name="groupid")
public Set<User> getUsers() {
return users;
}



User代码片段

@ManyToOne
@JoinColumn(name="groupid")
public Group getGroup() {
return group;
}



在执行这段代码时

@Test
public void testGetGroup(){
//testSaveGroup();

Session se=sf.getCurrentSession();
se.beginTransaction();
Group g=(Group)se.get(Group.class, 1);

se.getTransaction().commit();
for(User u : g.getUsers()){
//g.getUsers()
System.out.println("------------------");
System.out.println(u.getName());
}
}

会出现异常:

18:26:28,624 ERROR org.hibernate.LazyInitializationException:42 - failed to lazily initialize a collection of role: com.hibernate.crud.Group.users, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.hibernate.crud.Group.users, 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.initialize(AbstractPersistentCollection.java:365)
at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108)
at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:186)
at com.hibernate.crud.test.testGetGroup(test.java:69)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

也就是懒加载异常
failed to lazily initialize a collection of role: com.hibernate.crud.Group.users, no session or session was closed


经过马士兵老师的讲解,基本了解常形成的原因,现在大致谈一谈,当做个人笔记。

这是因为Hibernate Annotation的默认的FetchType在ManyToOne是EAGER的,在OneToMany上默认的是LAZY.

就是说这段代码中,User是FetchType.EAGER。 而Group是FetchType.LAZY。

具体是因为在这段代码中

@Test
public void testGetGroup(){
//testSaveGroup();

Session se=sf.getCurrentSession();
se.beginTransaction();
Group g=(Group)se.get(Group.class, 1);

se.getTransaction().commit();
for(User u : g.getUsers()){
//g.getUsers()
System.out.println("------------------");
System.out.println(u.getName());
}
}

执行 
Group g=(Group)se.get(Group.class, 1);
查询到的结果是

 select group0_.id as id1_0_, group0_.name as name1_0_ from t_group group0_ where group0_.id=?
只有group表的数据。

而要执行

for(User u : g.getUsers()){    

还需要连接数据库,但是session已经提交关闭了。所以会报 failed to lazily initialize a collection of role 异常。


要解决这个问题
1.可以在Group中设置FetchType.EAGER,得到对应的User表,缓存。如下:

@OneToMany(mappedBy="group",fetch=FetchType.EAGER )
@JoinColumn(name="groupid")
public Set<User> getUsers() {
return users;
}


2.将提交放在最后。如下:
@Test
public void testGetGroup(){
//testSaveGroup();

Session se=sf.getCurrentSession();
se.beginTransaction();
Group g=(Group)se.get(Group.class, 1);

for(User u : g.getUsers()){
//g.getUsers()
System.out.println("------------------");
System.out.println(u.getName());
}
se.getTransaction().commit();
}



现在正在学习hibernate,以后有其他方法或者错误,会有所更新。