业务并发现象带来的问题:秒杀 如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提供的乐观锁的实现原理分析。
1. 在表中添加version字段作为版本号,int型
2. 在表对应的实体类的version属性上加版本号属性
@Version
private Integer version;
3. 配置乐观锁的拦截器,MybatisPlusInterceptor
@Configuration
public class MpConfig {@Beanpublic 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=1Employee emp2 = employeeMapper.selectById(1); //version=1//2. 修改数据,假设emp2先修改完成,结果修改成功,version从1->2emp2.setEmail("zhangsan@qq.com");employeeMapper.updateById(emp2);//结果修改不成功emp1.setEmail("lisi@qq.com");employeeMapper.updateById(emp1);}