前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Mybatis-Plus使用乐观锁

Mybatis-Plus使用乐观锁

作者头像
乐心湖
发布2020-07-31 15:30:45
4230
发布2020-07-31 15:30:45
举报
文章被收录于专栏:MyTechnology

乐观锁面向场景

一件商品,成本价是80元,售价是100元。老板先是通知小李,说你去把商品价格增加50元。小李正在玩游戏,耽搁了一个小时。正好一个小时后,老板觉得商品价格增加到150元,价格太高,可能会影响销量。又通知小王,你把商品价格降低30元。

此时,小李和小王同时操作商品后台系统。小李操作的时候,系统先取出商品价格100元;小王也在操作,取出的商品价格也是100元。小李将价格加了50元,并将100+50=150元存入了数据库;小王将商品减了30元,并将100-30=70元存入了数据库。是的,如果没有锁,小李的操作就完全被小王的覆盖了。

现在商品价格是70元,比成本价低10元。几分钟后,这个商品很快出售了1千多件商品,老板亏1多万。。。

乐观锁与悲观锁

  • 上面的故事,如果是乐观锁,小王保存价格前,会检查下价格是否被人修改过了。如果被修改过了,则重新取出的被修改后的价格,150元,这样他会将120元存入数据库。
  • 如果是悲观锁,小李取出数据后,小王只能等小李操作完之后,才能对价格进行操作,也会保证最终的价格是120元。

接下来是基于SpringBoot+MP来完成乐观锁的搭配使用。

模拟冲突

数据库中增加商品表

代码语言:javascript
复制
CREATE TABLE product (
    id BIGINT ( 20 ) NOT NULL COMMENT '主键ID',
    name VARCHAR ( 30 ) NULL DEFAULT NULL COMMENT '商品名称',
    price INT ( 11 ) DEFAULT 0 COMMENT '价格',
    version INT ( 11 ) DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY ( id ) 
);

添加数据

代码语言:javascript
复制
INSERT INTO product (id, NAME, price) VALUES (1, '外星人笔记本', 100);

实体类

代码语言:javascript
复制
@Data
public class Product {
    private Long id;
    private String name;
    private Integer price;
    private Integer version;
}

Mapper接口类

代码语言:javascript
复制
@Repository
public interface ProductMapper extends BaseMapper<Product> {

}

测试,模拟的是开头讲到的场景

代码语言:javascript
复制
@SpringBootTest
public class ProductMapperTest {

    @Autowired
    private ProductMapper productMapper;

    @Test
    void testConcurrentUpdate() {
        //1、小李
        Product p1 = productMapper.selectById(1L);
        System.out.println(p1.getPrice());
        //2、小王
        Product p2 = productMapper.selectById(1L);
        System.out.println(p2.getPrice());
        //3、小李将价格加了50元,存入了数据库
        p1.setPrice(p1.getPrice() + 50);
        productMapper.updateById(p1);
        //4、小王将商品减了30元,存入了数据库
        p2.setPrice(p2.getPrice() - 30);
        int result = productMapper.updateById(p2);
        if (result == 0) {//更新失败,重试
            //重新获取数据
            p2 = productMapper.selectById(1L);
            //更新
            p2.setPrice(p2.getPrice() - 30);
            productMapper.updateById(p2);
        }
        //最后的结果
        Product p3 = productMapper.selectById(1L);
        System.out.println("最后的结果:" + p3.getPrice());
    }
}

解决方案(乐观锁注入)

原理

数据库中添加version字段 取出记录时,获取当前version

代码语言:javascript
复制
SELECT id,`name`,price,`version` FROM product WHERE id=1

更新时,version + 1,如果where语句中的version版本不对,则更新失败

代码语言:javascript
复制
UPDATE product SET price=price+50, `version`=`version` + 1 WHERE id=1 AND `version`=1

实现

实体类更新

对version字段添加@Version注解

代码语言:javascript
复制
@Data
public class Product {
    private Long id;
    private String name;
    private Integer price;
    @Version
    private Integer version;
}

进行一系列配置

创建包config,创建配置类MybatisPlusConfig

注意:此时拥有了删除配置类,就可以将启动类中的 @MapperScan 扫描注解 移动到这边。

然后注入乐观锁的Bean组件

代码语言:javascript
复制
@Configuration
@MapperScan("com.xn2001.mapper")
public class MybatisPlusConfig {

    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
    
}

回到原来的测试中继续测试,将数据库70重新改为100,运行测试类。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 乐观锁面向场景
  • 乐观锁与悲观锁
  • 模拟冲突
  • 解决方案(乐观锁注入)
    • 原理
      • 实现
      相关产品与服务
      数据库
      云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档