分布式锁实现方式~DB
本节重点
- 数据库分布式锁实现原理
- 掌握悲观锁和乐观锁
分布式锁实现方式
悲观锁
悲观锁是在数据修改之前,把待修改的数据进行锁定,防止并发修改。通常采用for update加锁方式来实现,使用时需要注意以下两点:
- 首先要开启事务
- 在for update语句中where条件字段上创建索引,因为是通过索引来加锁的,否则会锁整个表。
无事务的for update演练
模拟100个用户抢购商品,商品销售数量做加1操作,校验数据库中的销售数量是否是100,代码如下:
@DS(Constant.DataSource.MASTER)
@Override
public BaseResponse<BoolResult> testLock() {
GoodsInfo goodsInfo = baseMapper.selectOne(new LambdaQueryWrapper<GoodsInfo>().eq(GoodsInfo::getId,1)
.last(" for update"));
goodsInfo.setSaleCount(goodsInfo.getSaleCount() + 1);
Integer result = baseMapper.updateById(goodsInfo);
if (result != null && result.intValue() > 0) {
log.warn("testLock success!");
return BaseResponse.ok(new BoolResult(true));
} else {
log.warn("testLock fail!");
return BaseResponse.ok(new BoolResult(false));
}
}
结果:日志‘testLock success!’ 打印了 100条,而库中销售数量是2,显然和我们预期结果不一致。
有事务的for update演练
@DS(Constant.DataSource.MASTER)
@Transactional(rollbackFor = Exception.class)
@Override
public BaseResponse<BoolResult> testLock() {
GoodsInfo goodsInfo = baseMapper.selectOne(new LambdaQueryWrapper<GoodsInfo>().eq(GoodsInfo::getId,1)
.last(" for update"));
goodsInfo.setSaleCount(goodsInfo.getSaleCount() + 1);
Integer result = baseMapper.updateById(goodsInfo);
if (result != null && result.intValue() > 0) {
log.warn("testLock success!");
return B