Spring数据PESSIMISTIC_WRITE返回旧的DB值

时间:2017-03-01 11:08:56

标签: java spring spring-data persistence

我的界面中有这个方法,它扩展了CrudRepository:

@Lock(LockModeType.PESSIMISTIC_WRITE)
Voucher findTop1ByUsedFalseAndProductOrderByIdAsc(Product product);

这个组成部分:

@Component
@Transactional
public class VoucherFetchComponent {
    @Autowired
    private VoucherRepository voucherRepository;
public Voucher fetch(Product product) {
    Voucher voucher=voucherRepository.findTop1ByUsedFalseAndProductOrderByIdAsc(product);
    if(voucher==null)
       return null;
    voucher.setUsed(true);
    voucherRepository.save(voucher);
    return voucher;
}
}

问题是同时执行fetch()方法。 (假设我的数据库中只剩下1张优惠券)

我的期望:

1-服务A和B调用VoucherFetchComponent的fetch()方法

2-服务A(或B)锁定行,更新其中一个字段并返回

3-其他服务现在可以访问被锁定的行。但是现在查询与给定的条件(used = false)不匹配,因此返回null。

我得到了什么

1和2就像上面那样

3-其他服务返回旧对象,该对象具有参数(used = false)但之前已更新过!

1 个答案:

答案 0 :(得分:0)

如果仔细查看@Lock的javadoc,它会声明:

  

用于指定执行时要使用的LockModeType的注释   查询。

因此锁仅在查询执行期间处于活动状态..查询完成后...锁被释放。它在整个交易期间没有活动,正如您所期望的那样。

我建议使用标准锁定机制:

<强> VoucherRepository

public void lock(Voucher voucher, LockModeType lockType){

entityManager.lock(voucher, lockType);

<强> VoucherFetchComponent

public Voucher fetch(Product product) {
    Voucher voucher=voucherRepository.findTop1ByUsedFalseAndProductOrderByIdAsc(product);
    if(voucher==null)
       return null;
    voucherRepository.lock(voucher, LockModeType.PESSIMISTIC_WRITE);
    voucher.setUsed(true);
    voucherRepository.save(voucher);
    return voucher;
}

交易完成后,锁定将被释放。