使用hibernate.enable_lazy_load_no_trans解决休眠惰性初始化问题

我一直遭受臭名昭着的冬眠异常

org.hibernate.LazyInitializationException: could not initialize proxy - no Session

现在社区正在为之欢呼

<property name="hibernate.enable_lazy_load_no_trans" value="true"/>

说它解决了问题,但要谨慎使用它

他们谨慎使用它是什么意思?此属性实际上有什么作用?

请给我任何见解。提前致谢。


答案 1

这种方法的问题在于,你可以产生N+1效应。

假设您有以下实体:

public class Person{
    @OneToMany // default to lazy
    private List<Order> orderList;
}

如果您有一个返回 10K 人员的报告,并且在此报告中执行代码,则 JPA/Hibernate 将执行 10K 个查询。这是N + 1效应,您将无法控制将要执行的所有查询。person.getOrderList()

现在想象一下,订单如下:

public class Order{
    @OneToMany // default to lazy
    private List<EmailSent> emailSentList;
}

想象一下,现在你有一个迭代与 和 对于每个你将做一个 .你现在能看到问题吗?person.getOrderList()Order orderorder.getEmailSentList()

对于 LazyInitializationException,你可以有一些解决方案:

  • 使用 OpenInSessionInView 方法。您将需要创建一个将打开和关闭事务的 Web 筛选器。问题是N+1效应。
  • 使用hibernate.enable_lazy_load_no_trans配置,即休眠,如果需要,您将无法将项目移植到其他 JPA 提供程序。您还可以具有N + 1效果。
  • 使用名为 PersistenceContext Extended 的 EJB 功能部件。这样,您就可以保持多个事务的上下文打开。问题是:N + 1效应可能发生,使用大量服务器内存(实体将保持管理)
  • 在查询中使用 FETCH。使用这种方法,你可以做一个JPQL /HQL,比如:。使用此查询,您将从数据库加载列表,并且不会产生 N+1 效果。问题是你需要为每个情况编写一个JPQL。select p from Person p join fetch p.orderList

如果仍有任何问题,请检查以下链接:


答案 2

这与我们如何利用Hibernate通过会话概念实现可重复读取语义的方式背道而驰。首次加载对象时,如果在会话的生命周期内再次引用该对象,则无论该对象在数据库中是否已更改,都将返回相同的对象。这是休眠自动提供的可重复读取语义。

使用此设置时,您没有会话提供此保证,因此,如果您现在访问此数据,您将获得最新版本的数据。

这可能没问题。但请考虑以下情况:此对象长时间保存在某个位置,并且数据已发生很大变化,因此延迟获取的数据与会话处于活动状态时已加载的数据有很大不同。这是您需要关注的。

简单来说,如果您的程序不受以下因素的影响,则可以安全地使用此设置:在会话中已经获取的数据与将从会话中懒惰地提取的数据的过时程度

但是,如果这是一个问题(您的程序面临计时问题,当它可能一次工作正常而另一次失败时)是一个问题,那么在会话中获取所有必要的数据。


推荐