懒加载处理(Hibernate + Spring MVC)

4
什么是在Spring MVC应用程序中处理延迟加载对象的最佳解决方案?我已经对这个主题进行了一些搜索,找到了以下解决方案:
使用“打开视图会话”:为每个请求打开一个会话,并在视图渲染后关闭它。这种解决方案的问题在于,我还需要在Spring MVC模型之外(例如Junit测试用例)也进行延迟加载对象。另一个讨论该解决方案的问题是异常处理。如果事务在视图渲染期间抛出异常怎么办?
显式地打开会话:每当需要延迟加载对象时显式地打开会话。实际上,这个解决方案应该是可行的,但我认为这不是正确的方法。
使用AOP:创建一个方面,在会话中包装延迟加载方法。这可能是一个解决方案,但我不知道在我的应用程序的哪个级别定义Poitcuts。
创建自定义查询:为延迟加载和急切加载分别创建查询。这个解决方案实际上是可行的,但在我看来,它似乎是延迟加载模式的错误应用。

请查看有关 OSIV 优缺点的文章:http://blog.jhades.org/open-session-in-view-pattern-pros-and-cons/ - Angular University
使用自定义查询的问题在于它们强制执行与相关对象的连接,这并不总是最优解。有时,对于主对象使用1个查询和N个单独的查询来获取相关对象更加高效。 - Solubris
此外,将查询与延迟加载分开是很好的选择,因为这意味着您可以拥有一个单独的方法来进行延迟加载(例如:loadRelationsRequiredByDefault()),该方法可以被许多不同的查询重复使用,以返回相同的对象(或对象列表)。 - Solubris
2个回答

2

在所有情况下,都没有一种解决方案始终更好,问题在于服务层上的 @Transactional 在渲染阶段开始时不会保持会话开启。

会话在渲染开始之前被刷新、事务提交并关闭。

解决此问题的一种方法是使用自定义查询,根据正在构建的视图加载每个时刻所需的数据。

另一种方法是使用开放式会话视图,在渲染时保持会话打开,但这可能会因意外使用延迟加载而引起应用程序中的 N+1 问题。

此外,开放式会话视图可能会导致不可重复读取的问题,其中一些数据由服务层读取并用于提交事务,但当视图渲染开始时,该数据不再可用或已修改,并且对于构建视图非常重要。

请参见 JBoss Seam 团队关于 OSIV 使用的 postSeam 由许多与 Hibernate 相同的开发人员开发)。

不同的方法有不同的优缺点,取决于项目的优先事项。如果不必编写自定义查询很方便,因为有许多查询需要编写,则OSIV是一个很好的选择。偶尔出现的N+1问题可以逐个解决并接受。

如果强调要控制查询,因为应用程序例如对性能至关重要,则自定义查询是一种选择。

真正没有明确的最佳解决方案。如果您使用运行在客户端上的视图技术(如Angular.js)而不是服务器,则不会遇到这些问题,因为没有涉及服务器端呈现。


0

我不确定它是否符合您的要求,也不确定这是否是处理它的“正确”方式,但我使用了 @Transactional 注释。所以我的代码会是:

@Autowired
AccountDAO accountDAO; 

@Transactional
public List<String> getNamesOfAccount(String accountName){
    Account account = accountDAO.get(accountName);
    return account.getNames();
}

Account 中的 names 属性是延迟加载的,在返回之前才会加载。如果有更好的方法,请告诉我!


这可能是一个解决方案。我不知道是否是最好的方法。我会等待其他人的建议。 - scatolone
这个解决方案的好处在于,你只需要在DAO中使用EntityManager / SessionFactory。如果你不调用getNames(),那么什么也不会被加载。如果你调用了它,Spring会为你完成所有操作,你不需要打开Session或者其他什么。 - Jannik Weichert
让我不太信服的是,我无法通过域对象接口访问“惰性字段”,而只能通过DAO访问。 - scatolone
为什么?在我的情况下,账户是一个领域对象。有一次需要加载它。访问延迟字段“names”是没有DAO的。 - Jannik Weichert
如果您加载了一个账户实例,则在事务边界之外访问“names”字段时,必须先调用“getNamesOfAccount”,否则会出现LazyInitializationException异常。 - scatolone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接