在spring-boot项目中更改版本时,不会抛出OptimisticLockException

时间:2015-05-07 10:25:58

标签: spring-boot jpa spring-data-jpa

模型结构:

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

2 个答案:

答案 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 =?”,这将(由于显而易见的原因)不起作用。