我在 Spring 托管事务中遇到了一些奇怪的行为。这是一个 Spring MVC 应用程序。我将实体直接绑定到 Web 层。我使用以下服务层代码从数据库加载持久实体以进行编辑,该代码从使用@ModelAttribute 注释的方法调用。
@Transactional(readOnly = true)
@PreAuthorize("#id == authentication.principal.id or hasRole('ROLE_ADMIN')")
public User findById(Long id) {
return repository.findOne(id);
}
提交表单时,数据将绑定到此分离实体。作为验证的一部分,我查询数据库以验证为用户指定的电子邮件地址是唯一的。
@Transactional(readOnly = true)
public boolean isEmailAddressUnique(String emailAddress, Long userId){
return repository.checkEmailAddressUnique(emailAddress, userId) == 0;
}
此时,在执行此查询之前,Hibernate 会尝试刷新以前加载的我不理解的分离实体。显然,如果电子邮件地址不是唯一的,这会导致异常。
我正在使用 OpenEntityManagerinViewFilter 但是我希望这应该将 FlushMode 设置为 NEVER,也许不是。
如果我从 isEmailAddressUnique() 中删除 @Transactional 属性,则不会发生刷新,并且一切都按预期工作,我想这可以解决问题,但是我想了解这里发生了什么。
有什么建议么?
==============
好的,我已经进一步调查了。因此,我将 OpenEntityManagerInViewFilter 配置为默认值:
情景一。
[1] MVC 控制器在只读事务 T1 中加载用户实体 [2] 由于 MVC 字段绑定而修改了实体 [3] 第二个事务在只读事务 T2 中针对用户表运行。[4] Hibernate 刷新 T1 中加载的实体。[5] Hibernate 发出查询
情景 2。
子类化 OEMIVFilter 以将 FlushMode 设置为提交(默认为自动)。
如上所述,将步骤 [4] 和 [5] 颠倒过来,即。即使 T2 被标记为 readOnly Hibernate 仍然尝试在事务结束时刷新。我可以理解场景 1,因为 readOnly 可能只引用当前事务 T2(并且会在执行 T2 之前尝试同步数据库)。但是我希望在场景 2 中不应该发出 Flush。