休眠:无法延迟初始化角色集合,未关闭会话或会话

2022-09-01 12:33:57

我的代码:

    @Test
public void testAddRoleAndAddUser() {

    Role r = roleDao.findByProperty("name", "admin");
    if(r == null) {
        r = new Role();
        r.setName("admin");
        r.setDescription("Just administrator.");
        roleDao.save(r);
    }

    User u = dao.get(1l);
    Set<Role> roles = u.getRoleSet();
    logger.debug("Roles is null: " + (roles == null));
    roles.add(r);
    dao.save(u);
}

13:39:41,041 错误: org.hibernate.LazyInitializationException 无法懒惰地初始化角色集合: xxx.entity.core.User.roleSet, no session or session is closed org.hibernate.LazyInitializationException: 未能懒惰地初始化角色集合: xxx.entity.core.User.roleSet, 在 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.PersistentSet.add(PersistentSet.java:212) at sg.com.junglemedia.test.dao.impl.hibernate.UserDaoTest.testAddRoleAndAddUser(UserDaoTest.java:40) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) atsun.reflect.nativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.delegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) 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.statement.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.internal.runners.statement.RunBefores.evaluate(RunBefores.java:28) 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.runners.ParentRunner.run(ParentRunner.java:236) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46) 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)

有人帮忙吗?


答案 1

在实体类中,声明从用户到角色的映射时,请尝试将 fetchType 指定为 EAGER。像这样的东西:

@OneToMany(fetch=FetchType.EAGER)
public Collection<Role> getRoleSet(){
 ...
}

更新:最近收到此答案的评论使我重新审视了这个问题。自从我回答以来已经有一段时间了,当时我才开始使用Hibernate。拉斐尔和穆库斯说的话是合理的。如果你有一个大型集合,则不应使用急切提取。它共同选择映射到您的条目并加载到内存的所有数据。另一种方法是,每次需要处理相关集合时,即每次需要调用 getRoleSet 方法时,仍使用惰性提取并打开一个 Hibernate 会话。这样,Hibernate 将在每次调用此方法时对数据库执行选择查询,并且不会将集合数据保留在内存中。您可以在此处参考我的帖子以获取详细信息:http://khuevu.github.io/2013/01/20/understand-hibernate.html

也就是说,它可能取决于您的实际用例。如果集合数据很小,并且经常需要查询数据,则最好使用预先提取。我认为,在你的特定情况下,角色的集合可能非常小,适合使用急切的获取。


答案 2

您可以尝试将@Transactional注释添加到 Bean 或方法中(如果所有变量的声明都位于方法中)。


推荐