使用hibernate.enable_lazy_load_no_trans解决Hibernate

我一直在臭名昭著的冬眠异常


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

现在社区正在欢呼


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


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


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


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


拉莫斯之舞
浏览 1504回答 3
3回答

缥缈止盈

这种方法的问题是您可以产生N + 1效果。假设您具有以下实体:public class Person{&nbsp; &nbsp; @OneToMany // default to lazy&nbsp; &nbsp; private List<Order> orderList;}如果您有一个返回1万个人的报告,并且在此报告中执行了代码,person.getOrderList()那么JPA / Hibernate将执行10K查询。这是N + 1效果,您将无法控制将要执行的所有查询。现在想象一下,订单如下:public class Order{&nbsp; &nbsp; @OneToMany // default to lazy&nbsp; &nbsp; private List<EmailSent> emailSentList;}想象一下,现在您使用进行了一次迭代,person.getOrderList()并且每Order order做一次order.getEmailSentList()。现在可以看到问题了吗?对于LazyInitializationException,您可以有一些解决方案:使用OpenInSessionInView方法。您将需要创建一个WebFilter来打开和关闭事务。问题在于N + 1效应。使用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。

GCT1015

这违背了我们如何利用Session概念利用Hibernate对可重复读取语义的强制实施的优势。第一次加载对象时,如果在会话有效期内再次引用了该对象,则该对象将返回IRRESPECTIVE,以表明该对象在数据库中是否已更改。这是休眠自动提供的可重复读取语义。使用此设置,您没有会话可以提供此保证,因此,如果您现在访问此数据,则将获取该数据的最新版本。这可能很好。但是,请考虑以下情况:该对象在某个地方放置了很长时间,并且数据发生了很大变化,因此,延迟获取的数据与会话处于活动状态时已经加载的数据有很大不同。这是您需要关注的。简而言之,如果程序不受以下因素的影响,则可以安全地使用此设置:在会话中将已经获取的数据与将要从会话中延迟获取的数据相比如何过时但是,如果这(您的程序可能遇到计时问题,则它可能一次可以正常运行而又一次失败)则是一个问题,那么请在会话期间获取所有必要的数据。

守着一只汪

可能是因为有更好的解决方案,例如@Transactional,其中打开和关闭会话遵循一种非常普遍的模式:“打开一个会话,然后将所有内容包装在try-catch-finally中; catch回滚并最终关闭该会话。” 此批注通常在Web应用程序和服务的请求级别。或者,如果您需要更精细的控制,则可以使用SessionFactory手动打开会话。正如其他人所提到的,延迟加载是您需要注意的事情。这不是灵丹妙药,但它可能会非常有帮助。通常,如果您的应用程序设计为有许多小的请求,那么就可以了。急于加载也可能非常糟糕。例如,当您的对象模型具有许多多对多的关系,但是您的请求使用的数据深度不超过一层时。或者您现在可以忘记整个事情。使用延迟加载,直到出现问题为止。如果这样做的话,无论如何,您最好还是选择Mybatis。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java