一尘不染

使用hibernate.enable_lazy_load_no_trans解决Hibernate Lazy-Init问题

java

我一直在遭受着 hibernate异常

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

现在社区正在欢呼

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

说它可以解决问题,但请谨慎使用。

他们谨慎使用意味着什么?此属性实际上是做什么的?

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


阅读 1508

收藏
2020-03-19

共1个答案

一尘不染

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

假设你具有以下实体:

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

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

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

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

想象一下,现在你使用进行了一次迭代,person.getOrderList()并且每Order order做一次order.getEmailSentList()。现在可以看到问题了吗?

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

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