spring-boot 项目中版本更改时不会抛出 OptimisticLockException [英] OptimisticLockException not thrown when version has changed in spring-boot project

查看:18
本文介绍了spring-boot 项目中版本更改时不会抛出 OptimisticLockException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

模型结构:

@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:

Record in my database for my_entity:

编号:1版本:1...

id: 1 version: 1 ...

以下是我的更新方法:

void update(String id, Integer currentVersion, ....) {
    MyEntity myEntity = myRepository.findOne(id);
    myEntity.setVersion(currentVersion);
    // other assignments

    myRepository.save(myEntity);
}

以下是调用此方法时触发的查询.

Below is the query being fired when this method is invoked.

update my_entity set version=?, x=?, y=?, ...
where id=? and version=?

currentVersion 传入上述方法不是 1 时,我期待 OptimisticLockException.

I am expecting OptimisticLockException when currentVersion passed in above method is other than 1.

任何人都可以帮助我为什么我没有收到 OptimisticLockException?我正在为我的 webmvc 项目使用 spring-boot.

Can any body help me why I am not getting OptimisticLockException? I am using spring-boot for my webmvc project.

推荐答案

JPA 规范的第 11.1.54 节指出:

Section 11.1.54 of the JPA specification notes that:

一般情况下,使用 Version 指定的字段或属性应用程序不应更新注释.

In general, fields or properties that are specified with the Version annotation should not be updated by the application.

根据经验,如果您尝试手动更新版本字段,我可以建议某些 JPA 提供程序(OpenJPA 就是其中之一)实际上会抛出异常.

From experience, I can advise that some JPA providers (OpenJPA being one) actually throw an exception should you try to manually update the version field.

虽然不能严格回答您的问题,但您可以重新考虑以下因素,以确保 JPA 提供程序之间的可移植性以及严格遵守 JPA 规范:

While not strictly an answer to your question, you can re-factor as below to ensure both portability between JPA providers and strict compliance with the JPA specification:

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 节所述:

Assuming your update(...) method is running in a transaction however you still have an issue with the above as section 3.4.5 of the JPA specification notes:

3.4.5 OptimisticLockException Provider 实现可能会推迟写入数据库直到事务结束,当与有效的锁定模式和刷新模式设置一致.在在这种情况下,在提交时间之前可能不会发生乐观锁检查,并且 OptimisticLockException 可能会在before完成"阶段的提交.如果 OptimisticLockException 必须被应用程序捕获或处理,flush 方法应该是应用程序使用它来强制发生数据库写入.这将允许应用程序捕获和处理乐观锁例外.

3.4.5 OptimisticLockException Provider implementations may defer writing to the database until the end of the transaction, when consistent with the lock mode and flush mode settings in effect. In this case, an optimistic lock check may not occur until commit time, and the OptimisticLockException may be thrown in the "before completion" phase of the commit. If the OptimisticLockException must be caught or handled by the application, the flush method should be used by the application to force the database writes to occur. This will allow the application to catch and handle optimistic lock exceptions.

基本上,2 个用户可以同时提交对同一个实体的修改.两个线程都可以通过初始检查,但是当更新刷新到可能在事务提交中的数据库时,即在您的方法完成后,一个将失败.

Essentially then, 2 users can submit concurrent modifications for the same Entity. Both threads can pass the initial check however one will fail when the updates are flushed to the database which may be on transaction commit i.e. after your method has completed.

为了能够捕获和处理 OptimisticLock 异常,您的代码应如下所示:

In order that you can catch and handle the OptimisticLock exception, your code should then look something like the below:

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();
    }
}

这篇关于spring-boot 项目中版本更改时不会抛出 OptimisticLockException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆