延迟加载处理(Hibernate + Spring MVC)

时间:2014-01-24 15:56:07

标签: java spring hibernate spring-mvc

在Spring MVC应用程序中处理延迟加载对象的最佳解决方案是什么?我已经对这个主题进行了一些搜索,我找到了以下解决方案:

在视图中打开会话:为每个请求打开一个会话,并在视图呈现后关闭它。这个解决方案的问题是我还需要在Spring MVC模型之外的延迟加载对象(例如Junit测试用例)。另一个讨论该解决方案的问题是异常处理。如果事务在视图呈现期间抛出异常怎么办?

明确地打开会话:只要我需要延迟加载对象,就会明确地打开一个会话。实际上这个解决方案应该有效,但我认为这不是正确的方法。

使用AOP:创建一个在会话中包装延迟加载方法的方面。这可能是一个解决方案,但我不知道在我的应用程序的哪个级别我应该定义poitcuts

创建自定义查询:为延迟加载创建查询并为急切加载创建查询。这个解决方案实际上有效,但在我看来,延迟加载模式的错误应用

2 个答案:

答案 0 :(得分:2)

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

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

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

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

在视图中打开会话也可能导致不可重复读取出现问题,其中一些数据由服务层读取并用于提交事务,但是当视图呈现开始时,数据不再可用或被修改,并且对于构建视图很重要。

请参阅JBoss Seam团队的post关于使用OSIV的问题(Seam是由Hibernate开发的许多开发人员)。

根据项目的优先顺序,不同的方法有不同的优点和缺点。如果不必编写自定义查询的便利性是有意义的,因为有许多查询要编写,那么OSIV是一个不错的选择。偶然的N + 1问题可以逐案处理并与之共存。

如果重点是保持查询受控,因为应用程序的性能至关重要,那么自定义查询是一种选择。

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

答案 1 :(得分:0)

如果它符合您的要求,我不会感到舒服,而不是它是“正确”处理它的方法,但我使用了@Transactional Annotation。所以我会:

@Autowired
AccountDAO accountDAO; 

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

Account中的names属性是惰性的,并且在返回之前加载。 如果有更好的方式让我们听到!