乐观锁:在关系数据库管理系统里,乐观并发控制(又名“乐观锁”,Optimistic Concurrency Control,缩写“OCC”)是一种并发控制的方法。它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,那么会放弃修改。
简单来说,乐观锁主要解决的问题是当要更新一条记录的时候,希望这条记录没有被别人更新,如果别人更新了那么我就不更新了。
2.实现乐观锁的思路
乐观锁的实现方式:
数据库表中添加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提供的乐观锁的实现原理分析。
3.实现乐观锁的具体步骤
- 在数据库表上添加version列,我这里直接创建一个新表方便演示
CREATE TABLE goods ( id BIGINT(20) PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(32) NOT NULL, prices INT(10) NOT NULL , `version` INT(10) NOT NULL DEFAULT 1 ); INSERT INTO goods VALUES(NULL,'book',10,1); INSERT INTO goods VALUES(NULL,'computer',3000,1);
表的内容如下:
- 在模型类中添加对应的属性
@Data public class Goods { /** * 实现id自增长 */ @TableId(type = IdType.AUTO) private Integer id; private String name; //标记此属性为version列对应的属性 @Version private Integer version; }
- 添加乐观锁的拦截器
@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ //1 创建MybatisPlusInterceptor拦截器对象 MybatisPlusInterceptor mpInterceptor=new MybatisPlusInterceptor(); //2 添加乐观锁拦截器 mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mpInterceptor; } }
- 在测试类中执行更新操作
@SpringBootTest class SpringBootMypatisPlusApplicationTests { @Autowired private GoodsDao goodsDao; @Test void test() { Goods goods = new Goods(); goods.setId(1); goods.setPrices(100); goodsDao.updateById(goods); } }
通过结果我们可以发现,我们创建的这个对象并没有设置
version
数据,所以也就没有更新version
字段添加
version
数据@SpringBootTest class SpringBootMypatisPlusApplicationTests { @Autowired private GoodsDao goodsDao; @Test void test() { Goods goods = new Goods(); goods.setId(1); goods.setVersion(1); goods.setPrices(100); goodsDao.updateById(goods); } }
此时你可以发现,我们传递的是1,更新时会将version+1得到2,然后更新数据到数据库表里。
此时我们需要注意的是,我们设置的version数据就相当于上面讲的oldVersion,如果和数据库表中的不同,则sql更新失败
所以我们要想实现乐观锁,首先就是要得到表中要查找的那条数据的version,然后拿version当条件在将version加1更新回到数据库表中,所以我们在查询的时候,需要对其进行查询
@SpringBootTest class SpringBootMypatisPlusApplicationTests { @Autowired private GoodsDao goodsDao; @Test void test() { //1.先通过要修改的数据id将当前数据查询出来 //获得version字段值 Goods goods = goodsDao.selectById(1); //2.修改数据 goods.setPrices(200); goodsDao.updateById(goods); } }
现在我们来模拟一遍
秒杀
的过程,看看多人修改同一商品的时候,是不是只能有一个人修改成功。@SpringBootTest class SpringBootMypatisPlusApplicationTests { @Autowired private GoodsDao goodsDao; @Test void test() { //1.先通过要修改的数据id将当前数据查询出来 //获得version字段值 Goods goods1 = goodsDao.selectById(1); // version = 3 Goods goods2 = goodsDao.selectById(1); // version = 3 //2.修改数据 goods1.setPrices(1000); goodsDao.updateById(goods1);// 修改完后 version = 4 goods2.setPrices(1000); goodsDao.updateById(goods2);// 此时 oldversion的值已经发生变化,不在等于3,所以修改失败 } }
原文链接:https://blog.csdn.net/weixin_53029342/article/details/125609830