我的接口中有这个方法,它扩展了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()方法。(假设我的DB中只剩下1张凭单)
我所期望的:
1-服务A和B调用VoucherFetchComponent的fetch()方法
2-服务A(或B)锁定行,更新其中一个字段并返回
3-其他服务现在可以访问已锁定的行。但是现在查询不匹配给定的条件(used=false),所以它返回null。
我得到了什么,
1和2就像上面一样
3-另一个服务返回具有参数(used=false)的旧对象,但它以前已经更新过了!
发布于 2017-03-01 11:27:05
如果仔细查看@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;
}事务完成后,锁将被释放。
https://stackoverflow.com/questions/42530115
复制相似问题