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

Sac*_*rma 53 java persistence hibernate jpa lazy-initialization

我一直患有臭名昭着的hibernate异常

org.hibernate.LazyInitializationException: could not initialize proxy - no Session
Run Code Online (Sandbox Code Playgroud)

现在社区正在欢呼

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

说它解决了问题,但小心使用它.

他们的意思是谨慎使用它?这个属性实际上做了什么?

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

uai*_*ert 44

这种方法的问题在于你可以获得N + 1效果.

想象一下,你有以下实体:

public class Person{
    @OneToMany // default to lazy
    private List<Order> orderList;
}
Run Code Online (Sandbox Code Playgroud)

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

现在想象订单如下:

public class Order{
    @OneToMany // default to lazy
    private List<EmailSent> emailSentList;
}
Run Code Online (Sandbox Code Playgroud)

现在想象一下,你有一个迭代,person.getOrderList()并为Order order你做的每一个order.getEmailSentList().你现在能看到问题吗?

对于LazyInitializationException,您可以使用一些解决方案:

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

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

  • N + 1不是几个会话,而是数据库的几次旅行. (3认同)

cod*_*ler 11

这违背了我们如何利用Hibernate利用Session概念实现可重复读取语义的优势.首次加载对象时,如果在会话的生命周期内再次引用该对象,则返回相同的对象IRRESPECTIVE,该对象是否在DB中发生了更改.这是hibernate自动提供的可重复读取语义.

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

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

如果您的程序不受以下影响,您可以安全地使用此设置:在会话期间已经提取的数据与将从会话中拉出的数据失效的情况有多陈旧

但是如果这个(你的程序暴露于计时问题,它可能正常工作一次并且再次失败)是一个问题,那么在会话期间获取所有必要的数据.


Vla*_*cea 5

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

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

您永远不应该使用它,因为它们要么需要为 UI 呈现打开数据库连接(在视图中打开会话),要么需要为在初始持久性上下文 ( hibernate.enable_lazy_load_no_trans)之外获取的每个惰性关联都需要一个数据库连接。

有时,您甚至不需要实体,而DTO 投影甚至更好