其实乐观锁很常用不要觉得很难似的,一步步来试一下
乐观锁是先修改,更新的时候发现数据已经变了就回滚(check and set),乐观锁一般通过版本号或者时间戳实现。
这里我们使用Mybatis-Plus来进行使用
一.方法一使用 @Version 注解来实现
1.首先你要在你的表中添加一个字段这里我就定义为version用来控制版本
特别注意:
支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
2.接着你需要在你这个表的实体类中添加
@Version:可以在实体 bean 中使用@Version 注解,通过这种方式可添加对乐观锁定的支持 一个类中只能有一个@Version注解 注意此属性 不能用 String
@Version
private Integer version;
3.在Application容器创建Bean(很重要否则会提示找不到)
@Bean
public MybatisPlusInterceptor myOptimisticLockerInnerInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
4.最后这里贴一下我的业务处理代码吧,这就灵活使用了
@Override
public CommonResponse buyOne() {
GoodsInfo goodsInfo = goodsInfoMapper.selectById(1);
Integer inventoryNum = goodsInfo.getInventoryNum();
if (inventoryNum <= 0){
log.error("没有库存了!当前仓库为:"+inventoryNum);
return CommonResponseUtils.dataIsNullError("没有库存了!");
}
int newInventoryNum= inventoryNum - 1;//修改库存
goodsInfo.setInventoryNum(newInventoryNum);
int update = goodsInfoMapper.updateById(goodsInfo);//更新
if (update==1){
log.info("下单成功!当前仓库为:"+newInventoryNum);
return CommonResponseUtils.success("下单成功!当前仓库为:"+newInventoryNum);
}
log.error("下单失败!当前仓库为:"+newInventoryNum);
return CommonResponseUtils.dataIsNullError("下单失败!当前仓库为:"+newInventoryNum);
}
5.先看下我的数据库现在的库存5个
6.然后我用20的并发来测试看看,成功5个其他失败
再看下数据库,好了很成功!
二.其实原理还是依旧遵循
乐观锁是先修改,更新的时候发现数据已经变了就回滚
我们不使用方法一的@Version,这次相当于自己实现
这里我们就主要靠业务代码来实现了
思路:首先拿到一个库存数量 例如5,更新的时候一定要增加更新条件,那就是只有当前库存是5的时候才可以更新成功。(弊端1:失败次数多,2:如果有人增加库存那么的话。但是还是建议使用version方法一)
@Override
public CommonResponse buyOne() {
//查询商品
GoodsInfo goodsInfo = goodsInfoMapper.selectById(1);
//检测库存数量
Integer inventoryNum = goodsInfo.getInventoryNum();//当前库存数量
if (inventoryNum <= 0){
log.error("没有库存了!当前仓库为:"+inventoryNum);
return CommonResponseUtils.dataIsNullError("没有库存了!");
}
int newInventoryNum= inventoryNum - 1;//修改库存
goodsInfo.setInventoryNum(newInventoryNum);
QueryWrapper<GoodsInfo> query = Wrappers.query();
query.eq("inventory_num",inventoryNum);
int update = goodsInfoMapper.update(goodsInfo,query);//更新
if (update==1){
log.info("下单成功!当前仓库为:"+newInventoryNum);
return CommonResponseUtils.success("下单成功!当前仓库为:"+newInventoryNum);
}
log.error("下单失败!当前仓库为:"+newInventoryNum);
return CommonResponseUtils.dataIsNullError("下单失败!当前仓库为:"+newInventoryNum);
}