如何使用JPA和Hibernate解决LazyInitializationException

我正在为想要使用延迟初始化的客户开发一个项目。 当使用默认的延迟加载模式映射类时,他们总是会得到“懒惰的初始化exception”。

@JoinTable(name = "join_profilo_funzionalita", joinColumns = {@JoinColumn(name = "profilo_id", referencedColumnName = "profilo_id")}, inverseJoinColumns = {@JoinColumn(name = "funzionalita_id", referencedColumnName = "funzionalita_id")}) //@ManyToMany(fetch=FetchType.EAGER) - no exceptions if uncommented @ManyToMany private Collection<Funzionalita> funzionalitaIdCollection; 

有没有使用JPA类的标准模式来避免这个错误?

片段欢迎,非常感谢您的时间。

Hibernate 4.1.6终于解决了这个问题: https : //hibernate.atlassian.net/browse/HHH-7457

你需要设置hibernate-property hibernate.enable_lazy_load_no_trans = true

以下是在Spring中如何做到这一点:

 <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="myDataSource"/> <property name="packagesToScan" value="com.mycompany.somepackage"/> <property name="jpaVendorAdapter" ref="hibernateVendorAdapter"/> <property name="jpaDialect" ref="jpaDialect"/> <property name="jpaProperties"> <props> <prop key="hibernate.enable_lazy_load_no_trans">true</prop> </props> </property> </bean> 

瞧; 现在,您不必担心LazyInitializationException,而在hibernate-session之外导航域模型(在“JPA-speak”中的持久性上下文)

有很多预取属性的方法,所以在会话closures后它们在那里:

  1. 调用适当的getter。 在会话closures之后,字段被提取到bean中之后。
  2. 您可以初始化EJBQL查询中的字段,查找JOIN FETCH关键字。
  3. 如果您在支持它的Hibernate版本上启用AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS。

尝试这些解决scheme时可能会出现几个问题:

  1. getter的调用可以通过JIT编译器进行优化(有时需要一段时间)。
  2. 您尝试JOIN FETCH的实体可能通过涉及List的多个“多”关系链接。 在这种情况下,结果查询返回含糊不清的结果,Hibernate将拒绝在单个查询中获取数据。
  3. 已经有一个与AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS有关的有趣的bug 。 而且会有更多,因为hibernate的人说: 注意:这可能发生在事务之外,并不安全。 谨慎使用。 你主要靠自己。

最好的方法是先尝试一个JOIN FETCH 。 如果这不起作用,尝试getter方法。 如果JIT编译器在运行时被搞乱了,那么将结果赋给一个public static volatile Object

或者停止使用hibernate…

请注意,您不应该在Hibernate 4.1.7之前使用hibernate.enable_lazy_load_no_trans ,因为它会泄漏连接。 见https://hibernate.onjira.com/browse/HHH-7524

LazyInitializationException表示在hibernate会话closures后,或者在对象与会话分离之后调用集合。

您需要将对象重新挂接到hibernate会话,更改调用集合的位置,或将会话closures的边界移到更高层。

OpenSessionInView是处理这个问题的一种模式。 一些信息在这里:

http://www.hibernate.org/43.html

在实施这种模式时,您需要谨慎,并理解其中的含义。 每次在视图中导航一个惰性关联时,它都会触发另一个SQL查询来加载数据。 如果你的用例使得这些SQL查询的数量和大小很小,那么这可能就不重要了。 确保至less你调整你的日志logging设置,以便你可以看到什么样的查询Hibernate是在后台“神奇地”执行加载数据。

另外考虑你正在编写的应用程序的types。 如果你没有处理远程处理(没有Web服务,没有基于AJAX的Web客户端),那么OSIV可以很好地工作。 但是,如果远程序列化程序开始遍历整个对象图,则可能会触发大量的SQL查询,并损坏数据库和应用程序服务器。

在使用集合时,如果要使用延迟加载进行初始化,请在会话closures前使用该集合。 如果之后会话closures,如果你想使用,那么你会得到lazyinitializeException,因为懒惰是默认情况下尝试。

Oracle Java教程指出“企业bean支持事务,即pipe理共享对象并发访问的机制”。 所以,为了处理懒惰取指(Lazy Fetch)问题,我创build了一个无状态Java会话Bean,然后在从方法返回之前获取所需的所有子类。 这可以避免懒惰的读取exception。 Oracle也将其称为“Session Facade”核心J2EE模式。 这种模式似乎比其他一些提到的做法更好。

解决LazyInitializationException的最好方法是在实体查询中使用JOIN FETCH指令。

EAGER加载对性能不利。 此外,还有反模式,如:

  • 在视图中打开会话
  • hibernate.enable_lazy_load_no_trans

你不应该使用它,因为它们需要数据库连接为用户界面渲染打开(Open View in View),或者每个在初始持久化上下文( hibernate.enable_lazy_load_no_trans )之外获取的惰性关联都需要数据库连接。 。

有时候,你甚至不需要实体,而DTO投影就更好了。 只有在需要修改实体时才应该获取实体。 对于只读交易,DTO预测更好。

Interesting Posts