4.MyBatis-Plus乐观锁

4.MyBatis-Plus乐观锁

乐观锁和悲观锁

乐观锁

每次拿数据的时候都认为没有其他人修改数据内容,不会对数据上锁但在提交数据的时候会通过检查version字段来判断数据是否发生了变化。

悲观锁

每次拿数据的时候都认为有其他人要同时修改数据内容,因此每次在拿数据的时候都会对数据上锁,保证数据访问的排他性。

例子

这里引用尚硅谷视频中的一个例子:

一件商品,成本价80元,售价100元,老板让小李把售价提高50元,但小李手头有事没有马上处理。之后老板觉得定价过高,又通知小王,让小王把售价降低30元。而此时小李处理完了手头的事情,和小王同时登录了后台系统,同时对100元的商品价格进行修改。小李操作时,系统先取出商品价格100元;小王也在操作,取出的商品价格也是100元。小李将价格加了50元,并将100+50=150元存入了数据库;小王将商品减了30元,并将100-30=70元存入了数据库。如果在这个过程中没有锁,小李的操作就完全被小王的覆盖了。卖出一件商品就会亏损10元

在上面的情形中如果使用了乐观锁

  1. 小李先取出数据库中存放的100元和version(假定version字段的默认值为0)
  2. 小王取出数据库中的100元和version(值为0)
  3. 小李提交修改后的100+50=150元和更新后的version(值为1)
  4. 小王提交修改后的100-30=70元和更新后的version(值为1),发现数据库中的version值(1)与更新的version值(1)相同,说明在小王提交的数据有人修改过了
  5. 小王重新取出数据库中的150元和version(值为1)
  6. 小王提交更新后的150-30=120元和更新后的version(值为2)

如果使用了悲观锁

  1. 小李取出数据后对数据进行上锁
  2. 小王无法从数据库取出数据,只能等待小李操作完毕才能对价格进行修改
  3. 小李操作完毕,小王对价格进行修改
  4. 最后价格也是100+50-30=120元

两种锁的适用情形

乐观锁适用于读多写少的情况,在冲突发生的时候省去了锁的开销,提高系统吞吐量。

在写操作比较多的情况比较时候使用悲观锁,如果此时还使用乐观锁,在发生冲突的时候会频繁地进行重新获取和提交数据的操作,反而降低了性能。

模拟情形

数据表

字段名类型主键注释
idintYid
namevarcharN商品名
priceintN价格
versionintN乐观锁版本号
1.模拟修改冲突

实体类对象

package com.example.wx_test.entity;import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;@TableName("t_product")
@Data
public class Product {private Integer id;private String name;private Integer price;private Integer version;
}

mapper

package com.example.wx_test.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.wx_test.entity.Product;public interface ProductMapper extends BaseMapper<Product> {}

测试类

@Testpublic void withoutOptLock(){//不使用锁//小李查询商品价格Product li = productMapper.selectById(1);System.out.println("小李查询的价格:"+li.getPrice());//小王查询商品价格Product wang = productMapper.selectById(1);System.out.println("小王查询的价格:"+wang.getPrice());//小李将价格+50li.setPrice(li.getPrice()+50);productMapper.updateById(li);//小王将价格-30wang.setPrice(wang.getPrice()-30);productMapper.updateById(wang);//老板查询商品价格Product boss = productMapper.selectById(1);System.out.println("老板查询到的价格:"+boss.getPrice());}

运行结果:

小李查询的价格:100

小王查询的价格:100

老板查询到的价格:70

2.使用乐观锁并进行优化

product实体类添加@Version注解

package com.example.wx_test.entity;import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;@TableName("t_product")
@Data
public class Product {private Integer id;private String name;private Integer price;@Version//标识乐观锁版本号字段private Integer version;
}

在配置类中添加乐观锁插件

package com.example.wx_test.config;import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MybatisPlusConfig {//分页插件@Beanpublic PaginationInterceptor paginationInterceptor(){return new PaginationInterceptor();}//在配置类中添加乐观锁插件@Beanpublic OptimisticLockerInterceptor optimisticLockerInterceptor(){return new OptimisticLockerInterceptor();}
}

测试类

@Test
public void withOptLock(){//使用乐观锁//小李查询商品价格Product li = productMapper.selectById(1);System.out.println("小李查询的价格:"+li.getPrice());//小王查询商品价格Product wang = productMapper.selectById(1);System.out.println("小王查询的价格:"+wang.getPrice());//小李将价格+50li.setPrice(li.getPrice()+50);productMapper.updateById(li);//小王将价格-30wang.setPrice(wang.getPrice()-30);int result =productMapper.updateById(wang);(result==0){//操作失败,重试//重新获取商品信息wang = productMapper.selectById(1);System.out.println("小王重新查询的价格:"+wang.getPrice());//重新修改价格wang.setPrice(wang.getPrice()-30);}productMapper.updateById(wang);//老板查询商品价格Product boss = productMapper.selectById(1);System.out.println("老板查询到的价格:"+boss.getPrice());
}

运行结果:

小李查询的价格:100

小王查询的价格:100

小王重新查询的价格:150

老板查询到的价格:120

参考资料:

  1. https://www.bilibili.com/video/BV12R4y157Be?p=49&spm_id_from=pageDriver
  2. https://blog.csdn.net/hongchangfirst/article/details/26004335?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165119266916782246426992%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=165119266916782246426992&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-1-26004335.142v9pc_search_result_cache,157v4control&utm_term=%E4%B9%90%E8%A7%82%E9%94%81%E5%92%8C%E6%82%B2%E8%A7%82%E9%94%81&spm=1018.2226.3001.4187
  3. https://blog.csdn.net/sdyy321/article/details/6183412?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165119266916782246426992%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=165119266916782246426992&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-2-6183412.142v9pc_search_result_cache,157v4control&utm_term=%E4%B9%90%E8%A7%82%E9%94%81%E5%92%8C%E6%82%B2%E8%A7%82%E9%94%81&spm=1018.2226.3001.4187


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部