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