Java 惰性负载处理(Hibernate和Spring MVC)

Java 惰性负载处理(Hibernate和Spring MVC),java,spring,hibernate,spring-mvc,Java,Spring,Hibernate,Spring Mvc,在SpringMVC应用程序中处理延迟加载对象的最佳解决方案是什么?我已经对此主题进行了一些搜索,并找到了以下解决方案: 在视图中打开会话:为每个请求打开会话,并在视图呈现后关闭会话。这个解决方案的问题是,我需要延迟加载SpringMVC模型之外的对象(例如Junit测试用例)。关于此解决方案讨论的另一个问题是异常处理。如果事务在视图渲染期间引发异常,该怎么办 显式打开会话:每当需要延迟加载对象时,显式打开会话。事实上,这个解决方案应该有效,但我认为这不是正确的方法 使用AOP:创建一个方面,在

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

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

显式打开会话:每当需要延迟加载对象时,显式打开会话。事实上,这个解决方案应该有效,但我认为这不是正确的方法

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


创建自定义查询:创建惰性负载查询和急切负载查询。此解决方案实际上是可行的,但在我看来,这是一种错误的延迟加载模式应用

如果它符合您的要求,并且不是“正确”的处理方式,我就不是舒尔,但我使用了@Transactional注释。所以我会:

@Autowired
AccountDAO accountDAO; 

@Transactional
public List<String> getNamesOfAccount(String accountName){
    Account account = accountDAO.get(accountName);
    return account.getNames();
}
@Autowired
AccountDAO AccountDAO;
@交易的
公共列表GetNamesOfcount(字符串accountName){
Account=accountDAO.get(accountName);
return account.getNames();
}
Account中的names属性是惰性的,在返回之前加载。
如果有更好的方法,让我们听听

在所有情况下都没有更好的解决方案,问题是当呈现阶段开始时,服务层上的
@Transactional
将无法保持会话打开

在呈现开始之前,将刷新会话、提交事务并关闭会话

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

另一种方法是在视图中使用opensession,这会在渲染时保持会话打开,但由于无意中使用延迟加载,可能会在应用程序中导致N+1问题

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

从JBossSeam团队中可以看出,OSIV的使用经历了这些问题(我的许多开发人员都开发了Hibernate)

不同的方法有不同的优点和缺点,这取决于项目的优先级。如果不必编写自定义查询的便利性是有意义的,因为有许多查询需要编写,那么OSIV是一个不错的选择。局部N+1问题可以逐个解决,并与之共存

如果重点在于控制查询,例如,因为应用程序的性能至关重要,那么定制查询是一个选项


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

查看OSIV利弊的这篇文章使用自定义查询的问题是,它们会将连接强制到相关对象上,这并不总是最理想的解决方案。有时,对主对象使用1个查询,对相关对象使用N个单独的查询更有效。此外,将查询与延迟加载分开也很好,因为这意味着您可以使用单个方法进行延迟加载(例如:loadRelationsRequiredByDefault()),返回同一对象的多个不同查询可以重用该方法(或对象列表)。这可能是一个解决方案。我不知道这是否是最好的方法。我将等待其他人的建议。该解决方案的好处是,您的DAO中只有EntityManager/SessionFactory。如果您不调用getNames()没有加载任何内容。如果您使用Spring为您执行所有操作,并且您不必打开会话或其他内容。但让我无法信服的是,我无法通过域对象接口而只能通过DAO访问“惰性字段”。为什么?在我的情况下,帐户是一个域对象。需要加载一次。对惰性字段“名称”的访问没有DAO如果加载帐户实例,则在不调用“getNamesOfAccount”之前无法访问事务边界之外的字段“names”,否则将出现LazyInitializationException