Spring 数据 PESSIMISTIC_WRITE returns 旧数据库值
Spring data PESSIMISTIC_WRITE returns old DB value
我的接口中有这个方法,它扩展了 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)锁定该行,更新其中一个字段并 returns
3- 其他服务现在可以访问被锁定的行。但是现在查询不符合给定的条件 (used=false),所以它 returns null.
我得到的
1和2同上
3- 其他服务 returns 具有参数 (used=false) 但之前已更新的旧对象!
如果您仔细查看 @Lock 的 javadoc,它指出:
Annotation used to specify the LockModeType to be used when executing
the query.
所以锁仅在查询执行期间处于活动状态..查询完成后..锁被释放。它在整个交易期间并不像您预期的那样处于活动状态。
我建议使用标准锁定机制:
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;
}
事务完成后,锁将被释放。
我的接口中有这个方法,它扩展了 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)锁定该行,更新其中一个字段并 returns
3- 其他服务现在可以访问被锁定的行。但是现在查询不符合给定的条件 (used=false),所以它 returns null.
我得到的
1和2同上
3- 其他服务 returns 具有参数 (used=false) 但之前已更新的旧对象!
如果您仔细查看 @Lock 的 javadoc,它指出:
Annotation used to specify the LockModeType to be used when executing the query.
所以锁仅在查询执行期间处于活动状态..查询完成后..锁被释放。它在整个交易期间并不像您预期的那样处于活动状态。
我建议使用标准锁定机制:
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;
}
事务完成后,锁将被释放。