Hibernate:未能延迟初始化角色集合,没有会话或会话被关闭

Posted

技术标签:

【中文标题】Hibernate:未能延迟初始化角色集合,没有会话或会话被关闭【英文标题】:Hibernate: failed to lazily initialize a collection of role, no session or session was closed 【发布时间】:2011-03-31 22:46:49 【问题描述】:

我的代码:

    @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,没有 会话或会话已关闭 org.hibernate.LazyInitializationException: 未能延迟初始化 角色集合: xxx.entity.core.User.roleSet,没有 会话或会话于 org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380) 在 org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372) 在 org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:365) 在 org.hibernate.collection.PersistentSet.add(PersistentSet.java:212) 在 sg.com.junglemedia.test.dao.impl.hibernate.UserDaoTest.testAddRoleAndAddUser(UserDaoTest.java:40) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native 方法)在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 在 java.lang.reflect.Method.invoke(Method.java:597) 在 org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) 在 org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 在 org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) 在 org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) 在 org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) 在 org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) 在 org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) 在 org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) 在 org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) 在 org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) 在 org.junit.runners.ParentRunner.run(ParentRunner.java:236) 在 org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46) 在 org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

有人帮忙吗?

【问题讨论】:

save(u) 是做什么的?您如何管理Session?你在哪里打开/关闭它? 【参考方案1】:

就我而言,发生异常是因为我删除了 “hibernate.properties”文件中的“hibernate.enable_lazy_load_no_trans=true”...

我复制粘贴错字了...

【讨论】:

添加此属性后相同,它也对我有用。谢谢!【参考方案2】:

我遇到过这个问题,尤其是在 Jaxb + Jax-rs 编组实体时。我使用了预取策略,但我也发现提供两个实体是有效的:

    完整的实体,所有集合都映射为EAGER 删除了大部分或所有集合的简化实体

公共字段并在@MappedSuperclass 中映射并由两个实体实现扩展。

当然,如果您总是需要加载集合,那么没有理由不 EAGER 加载它们。在我的例子中,我希望在网格中显示实体的精简版本。

【讨论】:

【参考方案3】:

对我来说,它也适用于我在 eclipselink 中使用的方法。只需调用应该加载的集合的 size(),然后再将其用作页面的参数。

for (Entity e : entityListKeeper.getEntityList()) 
    e.getListLazyLoadedEntity().size();

这里 entityListKeeper 的实体列表具有 LazyLoadedEntity 列表。 如果您只有关系实体有 LazyLoadedEntity 列表,那么解决方案是:

getListLazyLoadedEntity().size();

【讨论】:

【参考方案4】:

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

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

更新: 最近收到的这个答案让我重新审视这个问题。自从我回答以来已经有一段时间了,当时我才开始使用 Hibernate。 Rafael 和 Mukus 说的是有道理的。如果你有一个大集合,你不应该使用急切的获取。它联合选择映射到您的条目的所有数据并加载到内存。另一种方法是在每次需要处理相关集合时(即每次需要调用 getRoleSet 方法)仍然使用延迟获取并打开 Hibernate 会话。这样,每次调用此方法时,Hibernate 都会对数据库执行选择查询,并且不会将集合数据保存在内存中。详情可以参考我的帖子:http://khuevu.github.io/2013/01/20/understand-hibernate.html

也就是说,这取决于您的实际用例。如果您的集合数据很小并且您经常需要查询数据,那么您最好使用急切获取。我认为,在您的具体情况下,角色集合可能非常小,适合使用急切获取。

【讨论】:

@vvekselva,可以参考这个问题:***.com/questions/2990799/… @Rafael +1。这不可能是一个解决方案。当父级有多个 OneToMany 或其中任何一个返回很多行时,则不会。当您只需要来自一个父级的数据时,为什么有人想要从其他表中返回数据。这是一个糟糕的糟糕的解决方案。我唯一想使用 EAGER 的情况是,如果它与此相反,并且仅表示一行(前提是它不会急切地加载加载其他内容的其他内容)。 github 帖子不见了。 =( 嗨@Fodder,有效链接在这里:khuevu.github.io/2013/01/20/understand-hibernate.html如果你有反馈,请告诉我 @KhueVu 请更新你的github链接!!是这个吗? khuevu.github.io/application-design-with-hibernate.html【参考方案5】:

我遇到了同样的问题,所以只是在我调用 DAO 方法的地方添加了 @Transactional 注释。它只是工作。我认为问题在于 Hibernate 不允许从数据库中检索子对象,除非在调用时特别是所有必需的对象。

【讨论】:

【参考方案6】:

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

【讨论】:

遇到了这个确切的错误,并意识到我需要一个 @Transactional 注释(用于我的 Spring 测试上下文),如此处所述。 您当然可以在您的生产代码中执行此操作,但您应该避免使您的测试方法具有事务性。否则,您将无法测试生产代码的正确事务处理【参考方案7】:

您有不同的选择来处理这个问题。似乎它把我们带回到了过去美好的普通 SQL 时代:)

阅读:http://www.javacodegeeks.com/2012/07/four-solutions-to-lazyinitializationexc_05.html

【讨论】:

【参考方案8】:

您尝试加载延迟加载的集合,但休眠会话已关闭或不可用。 这个问题的最佳解决方案,将延迟加载的对象更改为 eager fetch = FetchType.EAGER 加载。这个问题会解决的。

【讨论】:

【参考方案9】:

以下代码可能会导致类似的错误:

  using (var session = SessionFactory.OpenSession())
  using (var tx = session.BeginTransaction())
  
      movie = session.Get<Movie>(movieId);
      tx.Commit();
  
  Assert.That(movie.Actors.Count == 1);

你可以简单地修复它:

  using (var session = SessionFactory.OpenSession())
  using (var tx = session.BeginTransaction())
  
      movie = session.Get<Movie>(movieId);
      Assert.That(movie.Actors.Count == 1);
      tx.Commit();
  

【讨论】:

【参考方案10】:

您很可能会在 RoleDao 中关闭会话。如果您关闭会话然后尝试访问延迟加载的对象上的字段,您将收到此异常。您可能应该在测试中打开和关闭会话/事务。

【讨论】:

对我来说就是这种情况。在删除数据的过程中,我必须先从实体模型对象中复制出我需要的数据,然后再删除实体模型对象,最后才能将复制的数据用于其他用途。

以上是关于Hibernate:未能延迟初始化角色集合,没有会话或会话被关闭的主要内容,如果未能解决你的问题,请参考以下文章

未能延迟初始化角色集合:无法初始化代理 - Hibernate 中的 @ManyToMany 映射注释中没有会话错误? [复制]

Hibernate LazyInitializationException:未能延迟初始化角色集合

延迟初始化:未能延迟初始化集合

未能延迟初始化角色集合:com.pojo.Student.phonenos,没有会话或会话已关闭

org.hibernate.LazyInitializationException:无法延迟初始化角色集合:FQPropretyName,无法初始化代理 - 无会话

无法延迟初始化角色集合:myapp.myapp.models.Contact.messages,无法初始化代理 - 没有会话