【问题标题】:Hibernate: failed to lazily initialize a collection of role, no session or session was closedHibernate:未能延迟初始化角色集合,没有会话或会话被关闭
【发布时间】: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?你在哪里打开/关闭它?

标签: java hibernate


【解决方案1】:

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

我复制粘贴错字了...

【讨论】:

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

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

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

公共字段并在@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,可以参考这个问题:stackoverflow.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 中关闭会话。如果您关闭会话然后尝试访问延迟加载的对象上的字段,您将收到此异常。您可能应该在测试中打开和关闭会话/事务。

              【讨论】:

              • 对我来说就是这种情况。在删除数据的过程中,我必须先从实体模型对象中复制出我需要的数据,然后再删除实体模型对象,最后才能将复制的数据用于其他用途。
              猜你喜欢
              • 2011-12-11
              • 2011-07-18
              • 1970-01-01
              • 2011-03-03
              • 2014-11-02
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-08-13
              相关资源
              最近更新 更多