hibernate:LazyInitializationException:无法初始化代理

这是让我困惑的一个。 我试图实现一个基本的Hibernate DAO结构,但是有一个问题。

这是基本的代码:

int startingCount = sfdao.count(); sfdao.create( sf ); SecurityFiling sf2 = sfdao.read( sf.getId() ); sfdao.delete( sf ); int endingCount = sfdao.count(); assertTrue( startingCount == endingCount ); assertTrue( sf.getId().longValue() == sf2.getId().longValue() ); assertTrue( sf.getSfSubmissionType().equals( sf2.getSfSubmissionType() ) ); assertTrue( sf.getSfTransactionNumber().equals( sf2.getSfTransactionNumber() ) ); 

它在第三个assertTrue失败,它试图将sf中的值与sf2中的相应值进行比较。 这是一个例外:

 org.hibernate.LazyInitializationException: could not initialize proxy - no Session at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:86) at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:140) at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190) at com.freightgate.domain.SecurityFiling_$$_javassist_7.getSfSubmissionType(SecurityFiling_$$_javassist_7.java) at com.freightgate.dao.SecurityFilingTest.test(SecurityFilingTest.java:73) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:40) 

问题是,您正尝试访问分离的对象中的集合。 访问集合到当前会话之前,您需要重新附加对象。 你可以做到这一点

 session.update(object); 

使用lazy=false不是一个好的解决scheme,因为你抛弃了hibernate的Lazy Initialization特性。 当lazy=false ,集合在请求对象的同时加载到内存中。 这意味着,如果我们有一个包含1000个项目的集合,尽pipe我们要访问它们,但它们全都会被加载到内存中。 这不好。

请阅读这篇文章解释问题,可能的解决scheme,为什么这样实施。 此外,要了解会话和事务,您必须阅读这篇文章 。

这通常意味着拥有Hibernate会话已经closures。 您可以执行以下任一操作来修复它:

  1. 无论哪个对象创build这个问题,都使用HibernateTemplate.initialize(object name)
  2. 在你的HBM文件中使用lazy=false

看我的文章。 我有同样的问题 – LazyInitializationException – 这是我终于想出的答案:
http://community.jboss.org/wiki/LazyInitializationExceptionovercome
设置lazy = false并不是答案 – 它可以一次加载所有的东西,这不一定好。 例:
1个logging表参考文献:
5logging表B参考:
25条logging表C引用:
125logging表D

这只是可能出错的一个例子。
– 萨宾

如果你使用JPA批注的hibernate,那么这将是有用的。 在你的服务类中,应该有@PersistenceContext的实体pipe理器的setter。 将其更改为@PersistenceContext(type = PersistenceContextType.EXTENDED)。 那么你可以在任何地方访问懒的属性。

如果你正在使用Lazy加载你的方法必须注明

无状态会话EJB的@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)

我们也遇到了这个错误。 我们做了什么来解决这个问题是我们在Hibernate映射文件中添加了一个lazy = false

看来我们有一个类A,它在一个会话中加载另一个类B.我们试图访问类B上的数据,但是这个类B从会话中分离出来。

为了让我们访问这个B类,我们必须在类的Hibernate映射文件中指定lazy = false属性。 例如,

  <many-to-one name="classA" class="classB" lazy="false"> <column name="classb_id" sql-type="bigint(10)" not-null="true"/> </many-to-one> 

好吧,终于搞清楚我在哪里失职了。 我错误地认为我应该把每个DAO方法包装在一个事务中。 非常错误! 我已经吸取了教训。 我从所有DAO方法中拖出所有的事务代码,并严格在应用程序/pipe理器层build立事务。 这完全解决了我所有的问题。 数据是适当的惰性加载,因为我需要它,包装和closures一旦我做了提交。

生活是美好的… 🙂

如果您知道lazy=false的影响,并且仍然希望将其设置为默认值(例如,用于原型devise),则可以使用以下任一项:

  • 如果您正在使用XMLconfiguration:将default-lazy="false"到您的<hibernate-mapping>元素
  • 如果您使用注释configuration:将@Proxy(lazy=false)到您的实体类(es)

看来只有你的DAO正在使用会话。 因此,一个新的会话打开,然后closures每个DAO方法的调用。 因此,程序的执行可以恢复为:

 // open a session, get the number of entity and close the session int startingCount = sfdao.count(); // open a session, create a new entity and close the session sfdao.create( sf ); // open a session, read an entity and close the session SecurityFiling sf2 = sfdao.read( sf.getId() ); // open a session, delete an entity and close the session sfdao.delete( sf ); etc... 

默认情况下,实体中的收集和关联是懒惰的:它们是从数据库按需加载的。 从而:

sf.getSfSubmissionType().equals( sf2.getSfSubmissionType() )

抛出一个exception,因为它从数据库中请求一个新的加载,并且与实体加载相关的会话已经closures。

有两种方法可以解决这个问题:

  • 创build一个会议,以封闭我们所有的代码。 因此,这意味着要改变你的DAO内容,以避免打开第二个会话

  • 创build一个会话,然后更新(即重新连接)您的实体本会话之前的断言。

    了Session.update(对象);

如果您手动pipe理Hibernate会话,则可能需要查看sessionFactory.getCurrentSession()和相关文档:

http://www.hibernate.org/hib_docs/v3/reference/en/html/architecture-current-session.html

我认为Piko在他的回应中表示有hbm文件。 我有一个名为Tax.java的文件。 映射信息保存在hbm(= hibernate映射)文件中。 在类标签中有一个名为lazy的属性。 将该属性设置为true。 以下hbm示例显示了将lazy属性设置为false的方法

`id …'

如果你正在使用注释,而不是看在hibernate文档。 http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/

我希望有所帮助。

使用Hibernate.initialize作为懒惰字段

如果使用Spring和JPA注释,那么避免懒惰初始化中的会话问题的最简单的方法是重放:

 @PersistenceContext 

 @PersistenceContext(type = PersistenceContextType.EXTENDED) 

默认情况下,所有one-to-manymany-to-many关联在第一次被访问时会被延迟地获取。

在你的用例中,你可以通过把所有的DAO操作包装成一个逻辑事务来解决这个问题:

 transactionTemplate.execute(new TransactionCallback<Void>() { @Override public Void doInTransaction(TransactionStatus transactionStatus) { int startingCount = sfdao.count(); sfdao.create( sf ); SecurityFiling sf2 = sfdao.read( sf.getId() ); sfdao.delete( sf ); int endingCount = sfdao.count(); assertTrue( startingCount == endingCount ); assertTrue( sf.getId().longValue() == sf2.getId().longValue() ); assertTrue( sf.getSfSubmissionType().equals( sf2.getSfSubmissionType() ) ); assertTrue( sf.getSfTransactionNumber().equals( sf2.getSfTransactionNumber() ) ); return null; } }); 

另一个select是在加载实体时获取所有LAZY关联,以便:

 SecurityFiling sf2 = sfdao.read( sf.getId() ); 

也应该获取LAZY submissionType

 select sf from SecurityFiling sf left join fetch.sf.submissionType 

通过这种方式,您可以热切地获取所有惰性属性,并且也可以在Sessionclosures后访问它们。

您可以获取尽可能多的[one|many]-to-one关联和一个“一对多”的关联(由于运行笛卡尔积)。

要初始化多个“[一对|多]”,您应该在加载根实体之后使用Hibernate.initialize(collection) 。