在
Spring MVC应用程序中处理延迟加载对象的最佳解决方案是什么?我已经对这个主题进行了一些搜索,我找到了以下解决方案:
在视图中打开会话:为每个请求打开一个会话,并在视图呈现后关闭它.这个解决方案的问题是我还需要在Spring MVC模型之外的延迟加载对象(例如Junit测试用例).另一个讨论该解决方案的问题是异常处理.如果事务在视图呈现期间抛出异常怎么办?
明确地打开会话:每当我需要延迟加载对象时,明确地打开一个会话.实际上这个解决方案应该可行,但我不认为这是正确的方法.
使用AOP:创建一个在会话中包装延迟加载方法的方面.这可能是一个解决方案,但我不知道在我的应用程序的哪个级别我应该定义poitcuts
创建自定义查询:为延迟加载创建查询并为急切加载创建查询.这个解决方案实际上有效,但在我看来,懒惰负载模式的应用是错误的
最佳答案 在所有情况下都没有总是更好的解决方案,问题是服务层上的@Transactional在渲染阶段开始时不会保持会话打开.
在渲染开始之前刷新会话,提交事务并关闭会话.
解决此问题的一种方法是使用自定义查询,根据正在构建的视图加载每个时刻所需的数据.
另一种方法是在视图中使用开放会话,这会在渲染时保持会话打开,但由于意外使用延迟加载,它可能会在应用程序中引起N 1问题.
此外,在视图中打开会话可能会导致不可重复读取出现问题,其中一些数据由服务层读取并用于提交事务,但是当视图呈现开始时,数据不再可用或已被修改,这对于建立视图.
从JBoss Seam团队看到这个post对OSIV的使用经历了这些问题(Seam是我开发的许多与Hibernate相同的开发人员).
根据项目的优先顺序,不同的方法有不同的优缺点.如果不必编写自定义查询的便利性是有意义的,因为有许多查询要编写,那么OSIV是一个不错的选择.偶然的N 1问题可以逐案处理并与之共存.
如果重点是控制查询,因为应用程序是性能关键的,那么自定义查询是一种选择.
确实没有明确的最佳解决方案.如果您使用在客户端运行的视图技术(类似angular.js)而不是服务器,那么您不会遇到这类问题,因为不涉及服务器端呈现.