模型结构:
@MappedSuperclass
public class BaseModel<K extends Comparable> implements Serializable, Comparable<Object> {
private static final long serialVersionUID = 1L;
@Id
private K id;
@Version
private Integer version;
// getter/setter
}
@Entity
public class MyEntity extends BaseModel<String> {
// some fields and it's getter/setter
}
在我的数据库中记录my_entity
:
id:1 版本:1 ...
以下是我的更新方法:
void update(String id, Integer currentVersion, ....) {
MyEntity myEntity = myRepository.findOne(id);
myEntity.setVersion(currentVersion);
// other assignments
myRepository.save(myEntity);
}
以下是调用此方法时触发的查询。
update my_entity set version=?, x=?, y=?, ...
where id=? and version=?
当上述方法中传递的currentVersion
不是1
时,我期待OptimisticLockException。
任何身体都可以帮助我为什么我没有得到OptimisticLockException? 我在我的webmvc项目中使用spring-boot。
答案 0 :(得分:4)
JPA规范第11.1.54节指出:
通常,使用版本指定的字段或属性 应用程序不应更新注释。
根据经验,如果您尝试手动更新版本字段,我可以建议一些JPA提供程序(OpenJPA是其中一个)实际抛出异常。
虽然不是严格地回答您的问题,但您可以重新考虑以下因素,以确保JPA提供商之间的可移植性和严格遵守JPA规范:
public void update(String id, Integer currentVersion) throws MyWrappedException {
MyEntity myEntity = myRepository.findOne(id);
if(currentVersion != myEntity.getVersion()){
throw new MyWrappedException();
}
myRepository.save(myEntity);
//still an issue here however: see below
}
假设您的update(...)
方法正在一个事务中运行,但是您仍然遇到上述问题,如JPA规范第3.4.5节所述:
3.4.5 OptimisticLockException提供程序实现可以推迟写入数据库,直到事务结束时为止 与锁定模式和冲洗模式设置一致有效。在 在这种情况下,在提交时间之前可能不会发生乐观锁定检查, 并且可以在&#34;之前抛出OptimisticLockException 完成&#34;提交阶段。 如果必须使用OptimisticLockException 被应用程序捕获或处理时,应该使用flush方法 应用程序用来强制数据库写入发生。这个 将允许应用程序捕获并处理乐观锁定 异常。强>
基本上,2个用户可以为同一个实体提交并发修改。两个线程都可以通过初始检查,但是当更新被刷新到数据库时可能会失败,这可能是在事务提交时,即在您的方法完成之后。
为了能够捕获并处理OptimisticLock异常,您的代码应该如下所示:
public void update(String id, Integer currentVersion) throws MyWrappedException {
MyEntity myEntity = myRepository.findOne(id);
if(currentVersion != myEntity.getVersion()){
throw new MyWrappedException();
}
myRepository.save(myEntity);
try{
myRepository.flush()
}
catch(OptimisticLockingFailureException ex){
throw new MyWrappedException();
}
}
答案 1 :(得分:0)
使用JPA时,在更新前使用EVICT。我也没有让@Version工作。该属性已增加,但在更新具有错误版本属性的对象时未引发异常。
我唯一需要做的就是首先EVICT对象,然后保存它。如果Version属性不匹配,则抛出HibernateOptimisticLockingException。
将休眠ShowSQL设置为'true'以验证实际更新sql以“where id =?和version =?”结尾。如果首先没有驱逐对象,则update语句只有“where id =?”,这将(由于显而易见的原因)不起作用。