所有
我们正在使用Hibernate 4.2.14.Final
,Hibernate JPA API 2.0
和Spring Data JPA 1.7.0.RELEASE
。我们的交易通过JTA Container管理的交易进行管理。
我看到一个问题,如果子实体没有任何变化,子实体的版本计数器在save and flush
之后错误地返回。但是,在实体上调用refresh
会“修复”它。
举一个简单的例子来说明,假设我们有DepartmentEntity
和EmployeeEntity
以及Department和Employee之间的一对多关系。
我们还有反映关系的DTO,因为我们不希望在我们的服务API中公开JPA注释的实体,所以我们也使用它们。
public class EmployeeEntity {
...
@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST},
optional = false)
@JoinColumn(name = "DEPARTMENT_ID", nullable = false)
private DepartmentEntity department;
...
}
我在Spring管理的Bean中有一个服务方法:
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public <EmployeeDTO> update(EmployeeDTO employee) {
// Code here to retrieve the EmployeeEntity by Unique ID and copy props
// from EmployeeDTO to EmployeeEntity, and also DepartmentDTO to
// DepartmentEntity.
...
// EmployeeRepository is a Spring Data JPA Repository
employeeEntity = employeeRepository.saveAndFlush(employeeEntity);
// Convert EmployeeEntity back to EmployeeDTO and return it
return newEmployeeDTOinstance;
}
如果我们开始:员工v1,部门v1,我们只更改了部门,会发生的事情是在saveAndFlush
之后(通过调试器检查),我看到员工v2和部门v2。
然而,当整个事务完成并且我通过PL / SQL Developer检查数据库行时,Employee保持在版本1,而Department处于版本2。
下一次更新调用我传入了Employee v2和Department v2(因为这是JPA / Hibernate告诉我的最新版本)。但是,该数据库具有Employee版本1,并且我爆发了乐观锁定异常。
我可以通过在saveAndFlush之后调用refresh来“使其工作”,如下所示......
// EmployeeRepository is a Spring Data JPA Repository
employeeEntity = employeeRepository.saveAndFlush(employeeEntity);
// Refresh after flush in order to ensure version numbers are correct on Entities.
employeeRepository.refresh(employeeEntity);
在Employee没有更改但部门没有更改的情况下,在saveAndFlush之后,我看到Employee v2,然后调用refresh将Employee设置回v1。
我的问题是 为什么? JPA / Hibernate假设通过在实体上调用saveAndFlush,版本计数器应该递增,但是在结束时事务看到没有更改,因此实际上没有更改数据库中的行?
有没有人曾经遇到过这个?任何见解或我可以看到的地方?
我确实读过这个Stackoverflow的回答,暗示了刷新后刷新:https://stackoverflow.com/a/8137376/463196
然而,它没有解决版本计数器问题,而且似乎更多的是刷新通过数据库触发器进行的更改,因为我们让Hibernate管理版本计数器。
非常感谢你!