0

我在 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。

4

1 回答 1

2

我一开始也有同样的问题。我们还使用了 OSIV 过滤器,我们的问题是事务注释上的只读标志没有传播到休眠。我们必须确保我们使用正确的事务管理器,更重要的是使用 hibernatevendoradapter。检查您的配置,如果您无法解决问题,请发布您的持久性和弹簧集成配置。

于 2013-04-18T07:30:10.877 回答