mybatis-plus实现乐观锁

一、场景

业务并发现象带来的问题:秒杀   如12306抢票,抢商品

1. 假如有100张票在出售,为了保证每张票只能被一个人购买,如何保证不会出现超买或者重复卖

2.对于这一类问题,其实有很多的解决方案可以使用

3. 第一个首先想到的是锁,锁在一台服务器中时可以解决的,但是如果在多台服务器下,锁就没有办法控制,比如12306有两台服务器在进行卖票,在两台服务器上都加锁的话,那也可能会导致在同一时刻有两个线程在进行卖票,还是会出现并发问题。

4. 接下来介绍的这种方式就是针对小型企业的解决方案,因为数据库本身的性能就是个瓶颈,如果对其并发量超过2000以上的就需要考虑其他的解决方案了。

二、乐观锁

在关系数据库管理系统中,乐观并发控制是一种并发控制的方法。它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的部分数据。在提交数据之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,那么会放弃修改。

简单来说,乐观锁主要解决的问题是当要更新一条记录的时候,希望这条记录没有被别人更新,如果别人更新了那么我就不更新了。

三、乐观锁的实现方式

数据库表中添加version列,比如默认值给1
第一个线程要修改数据之前,取出记录时,获取当前数据库中的version=1
第二个线程要修改数据之前,取出记录时,获取当前数据库中的version=1
第一个线程执行更新时,set version = newVersion where version = oldVersion
newVersion = version+1 [2] (表示更新后的值)
oldVersion = version [1] (表示取出记录时的值)
第二个线程执行更新时,set version = newVersion where version = oldVersion
newVersion = version+1 [2]
oldVersion = version [1]
假如这两个线程都来更新数据,第一个和第二个线程都可能先执行
假如第一个线程先执行更新,会把version改为2,
第二个线程再更新的时候,set version = 2 where version = 1,此时数据库表的数据version已经为2,所以第二个线程会修改失败
反之同理
不管谁先执行都会确保只能有一个线程更新数据,这就是MP提供的乐观锁的实现原理分析。

四、mybatis-plus实现乐观锁的步骤

1. 在表中添加version字段作为版本号,int型

2. 在表对应的实体类的version属性上加版本号属性

@Version
private Integer version;

3. 配置乐观锁的拦截器,MybatisPlusInterceptor

  • 创建config包
  • 创建MpConfig的配置类,拦截器类型为MybatisPlusInterceptor
@Configuration
public class MpConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

五、乐观锁的使用

想要实现乐观锁,首先就是要得到表中要查找的那条数据的version,然后拿version当条件,再将version加1更新回到数据库的表中。所以需要先对其进行查询。

@Test
void testLock(){
        //1.先通过要修改的数据Id,将当前数据查询出来
        //获得version字段值
        Employee emp1 = employeeMapper.selectById(1); //version=1
        Employee emp2 = employeeMapper.selectById(1); //version=1
        //2. 修改数据,假设emp2先修改完成,结果修改成功,version从1->2
        emp2.setEmail("[email protected]");
        employeeMapper.updateById(emp2);
        
        //结果修改不成功
        emp1.setEmail("[email protected]");
        employeeMapper.updateById(emp1);
    }

你可能感兴趣的:(mybatis-plus,数据库,spring,boot)