乐观锁场景描述及代码实现

乐观锁场景描述及代码实现

1.使用场景

乐观锁概念描述每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据
乐观锁使用场景乐观锁主要是针对并发下,多读少写的场景,资源提交冲突(例如下面例子),其他使用方需要重新读取资源,会增加读的次数,但是可以面对高并发场景,前提是如果出现提交失败,用户是可以接受的。因此一般乐观锁只用在高并发、多读少写的场景。

2.代码实现(基于版本号方式实现)
举一个简单的例子:假设数据库中账户信息表中有一个version字段,当前值为1;而当前账户余额字段为100;
1、操作员A此时将其读出(version=1),并从其账户余额中扣除50(100-50);
2、在操作员A操作的过程中,操作员B也读入此用户信息(version=1),并从其账户余额中扣除20(100-20);
3、操作员A完成了修改操作,将数据版本号+1(version=2),连同账户扣除后余额(余额剩余50,提交至数据库更新,此时由于 提交数据库版本大于数据库当前记录的版本,数据被更新,数据库记录version更新为2
4、操作员B完成了操作,也将版本号+1(version=2)试图向数据库提交数据余额剩余80,但此时比对数据库记录版本时发现,操作员B提交的数据版本号为2,数据库记录当前版本也为2,不满足“提交版本必须大于记录当前版本才能执行更新”的乐观锁策略,因此,操作员B的提交被驳回。 这样就避免了操作员B用基于version=1的旧数据修改的结果覆盖操作员A的操作结果的可能。

…以下是一段扣除库存的代码,使用乐观锁实现实体及sql语句:

库存表: CREATE TABLE storage (
id int NOT NULL AUTO_INCREMENT,
commodity_code varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT ‘商品code’,
count int DEFAULT ‘0’ COMMENT ‘商品数量’,
version int DEFAULT ‘1’ COMMENT ‘版本号’,
PRIMARY KEY (id),
UNIQUE KEY commodity_code (commodity_code)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb3 COMMENT=‘库存’;

1.实现层
public DefaultResponse updateStorage(StorageDTO storageDTO) {
    try {
        log.info("用户"+storageDTO.getUser()+"开始扣除库存=========>");
        QueryWrapper<Storage> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Storage::getCommodityCode, storageDTO.getCommodityCode());
        Storage storageResult = baseMapper.selectOne(wrapper);
        //如果当前订单编号存在,并且库存数量大于下单数量的时候开始扣库存
        if (storageResult != null && storageResult.getCount() > storageDTO.getCount()) {
           //这里用sleep主要是为了体现多个线程同时争夺扣库存
            Thread.sleep(5000);
            storageResult.setCount(storageResult.getCount() - storageDTO.getCount());
            int i = storageMapper.upStockByCode(storageResult);
            if (i > 0) {
                log.info(storageDTO.getUser()+"库存扣除成功=========>");
                return DefaultResponse.ok(storageDTO.getUser() + ": 库存扣除成功");
            }
        }
        return new DefaultResponse(StatusCode.ERROR, storageDTO.getUser() + " :库存扣除失败");
    } catch (Exception ex) {
        return new DefaultResponse<>(StatusCode.ERROR, ex.getMessage());
    }
}



2.sql层级代码
<update id="upStockByCode">
      update storage set count = #{count},version = version + 1  where version = #{version} and commodity_code = #{commodityCode}
</update>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值