Mybatis-Plus初步使用乐观锁悲观锁

1.乐观锁

**作用:**当要更新一条记录的时候,希望这条记录没有被别人更新,从而减少线程冲突导致的问题
乐观锁的实现方式:

取出记录时,获取当前 version 更新时,带上这个 version 执行更新时, set version = newVersion
where version = oldVersion 如果 version 不对,就更新失败

场景

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

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

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

实体类加入version注解

//乐观锁version注解
    @Version
    private Integer version;

编写配置类

@Configuration
@EnableTransactionManagement
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        //创建MybatisPlusInterceptor拦截器对象
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        paginationInnerInterceptor.setOptimizeJoin(true);
        paginationInnerInterceptor.setDbType(DbType.MYSQL);
        paginationInnerInterceptor.setOverflow(true);
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        //添加乐观锁拦截器
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

调用service方法

    @GetMapping("/OCC")
    @Operation(summary = "乐观锁",description = "乐观锁")
    public Result OCC(String id,String name){
        Users users = iUsersService.getById(id);
        users.setName("xxxxx");
        users.setEmail("sadasdasd");
        iUsersService.updateById(users);
        return Result.success(users);
    }

观察输出信息

image.png

发现执行修改操作时会判断当前version

支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
整数类型下 newVersion = oldVersion + 1
newVersion 会回写到 entity 中
仅支持 updateById(id) 与 update(entity, wrapper) 方法
在 update(entity, wrapper) 方法下, wrapper 不能复用!!!
调用 updateById 方法更新数据库中的记录。在这个过程中,MyBatis-Plus 会自动检查版本号或时间戳,如果数据库中的记录被其他事务修改了,那么这个更新操作就会失败。

乐观锁与悲观锁

如果是乐观锁,小王保存价格前,会检查下价格是否被人修改过了。如果被修改过了,则重新取出的被修改后的价格,150元,这样他会将120元存入数据库。

如果是悲观锁,小李取出数据后,小王只能等小李操作完之后(有一个操作的时候另一人操作会被阻塞也就是无法操作),才能对价格进行操作,也会保证最终的价格是120元。(也就是说你先弄 你弄完之后我才能弄;也就不会导致上面的问题)

@GetMapping("/OCC")
    @Operation(summary = "乐观锁",description = "乐观锁")
    public Result OCC(String id){
        Users suhai = iUsersService.getById(id);
        System.out.println("suhai.getAge() = " + suhai.getAge());
        Users suyue = iUsersService.getById(id);
        System.out.println("suyue.getAge() = " + suyue.getAge());
        //suhai操作年龄-5
        suhai.setAge(suhai.getAge()-5);
        iUsersService.updateById(suhai);
        //suyue操作年龄+3
        suyue.setAge(suyue.getAge()+3);
        iUsersService.updateById(suyue);
        //调用 updateById 方法更新数据库中的记录。在这个过程中,
        // MyBatis-Plus 会自动检查版本号或时间戳,如果数据库中的记录被其他事务修改了,那么这个更新操作就会失败。
        return Result.success("模仿成功");

    }

这是一个demo 如果suhai进行操作 则version会自动+1 而suyue再线程进行操作 则会判断当前version是否相同 如果不同则操作失败 不会执行接下来的语句

悲观锁

悲观锁解决方案非常简单 直接在操作sql中添加 for update语句即可

select id,商品名,商品价格,version from 商品表 where id =2 for update
使用 for update操作 可以认为是给每次操作都加上表级别的悲观锁 在事务没结束前 其他事务必须等待加锁的事务提交后才可以
并发环境下都不建议使用悲观锁,因为悲观锁容易锁表,导致事务等待,性能低下。 

批量查询

   //  测试批量查询!
     @Test
     public void testSelectByBatchId(){
     List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
     users.forEach(System.out::println);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值