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

查看:132
本文介绍了在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:

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

通常,使用版本指定的字段或属性 批注不应由应用程序更新.

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提供程序实现可以将对数据库的写操作推迟到事务结束时,此时 与有效的锁定模式和冲洗模式设置一致.在 在这种情况下,可能要等到提交时间后才能进行乐观的锁定检查, 并且OptimisticLockException可能会在之前 完成"阶段提交.如果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.

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

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天全站免登陆