还不会用乐观锁吗?Spring Cloud Alibaba组合Mybatis-Plus真香

2022-09-23 17:49:02 浏览数 (1)

当我们想要在业务中引入“乐观锁”时,应该要思考清楚它的概念,为了更加形象的理解“乐观锁”,我们可以先看一下认识下悲观锁。

什么是悲观锁

顾名思义,悲观锁是基于一种悲观的态度来防止一切数据冲突,它是以一种预防的姿态,并在修改数据之前把数据锁住,然后再对数据进行读写。在它释放锁之前任何线程都不能对其数据进行操作,直到持有锁的线程释放锁之后,其它线程才能通过竞争去获取到悲观锁,自动对数据进行加锁,然后才可以对数据进行操作;

很多技术类的文章中,也将“悲观锁”叫做“互斥锁”或者“排它锁”。

悲观锁的特点:可以完全保证数据的独占性和正确性,因为每次请求都会先对数据进行加锁, 然后进行数据操作,最后再解锁,而加锁释放锁的过程会造成消耗,所以性能不高;

在Java中最常见的悲观锁就是synchronized和ReentrantLock,前者是隐式加锁,后者是显式加锁。

代码语言:javascript复制
Object lock=new Object();
    public void test1(){
    synchronized (lock){
        //添加需要加锁的逻辑
    }

ReentrantLock reentrantLock=new ReentrantLock();
    public void test2(){
        reentrantLock.lock();
        try {
            //添加需要加锁的逻辑
        }catch (Exception e){
        }finally{
            reentrantLock.unlock();
        }
    }

在数据库中,比如MySQL,我们可以通过添加“for update”加一个行锁,当然也可以叫“排它锁”。

代码语言:javascript复制
###添加一个悲观锁
SELECT * FROM user WHERE id=3 FOR UPDATE;

什么是乐观锁

顾名思义,乐观锁是对于数据冲突保持一种乐观态度,操作数据时不会对操作的数据进行加锁(这使得多个线程可以并行的对数据进行操作),只有到数据提交的时候才通过一种机制来验证数据是否存在冲突(一般实现方式是通过加版本号然后进行版本号的对比方式实现);

特点:乐观锁是一种并发类型的锁,其本身不对数据进行加锁而是通过业务实现锁的功能。那么不对数据进行加锁就意味着允许多个请求同时访问数据,同时也省掉了对数据加锁和解锁的过程,这种方式因为节省了悲观锁加锁的操作,所以可以一定程度的的提升性能。不过在并发非常高的情况下,会导致大量的请求冲突,冲突导致大部分操作无功而返而浪费资源,所以在高并发的场景下,乐观锁的性能反而不如悲观锁。

在Java中,我们也可以将读写锁ReentrantReadWriteLock当作乐观锁的一种变种,当然最经典的乐观锁就是Java中的CAS,Java的JUC中用到乐观锁的地方,几乎都是用CAS实现的。

在MySQL中,最常见的乐观锁就是“版本号”,并在需要加乐观锁的表中添加一个字段用来记录版本号,比如最常见的就是“version字段”。

Spring Cloud Alibaba组合Mybatis-Plus真香

一般情况下,业务服务中使用的乐观锁最多的业务场景就是数据库,也就是添加“version”字段。如果是所有的表都要添加乐观锁,那么软件开发人员需要在所有的业务服务中,添加一遍乐观锁的逻辑,比如版本号的校验等等,太麻烦了。

使用Spring Cloud Alibaba组合Mybatis-Plus,添加乐观锁就只需要几行代码就行。

第一步,在数据库的业务表中添加一个“version”字段;

第二步,以Spring Cloud Alibaba作为基础框架,初始化一个微服务;

第三步,在微服务中添加如下pom依赖。

代码语言:javascript复制
<!—引入Mybatis Plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>
<!—引入Mybatis-->

 <dependency>
    <groupId>org.mybatis</groupId>
     <artifactId>mybatis</artifactId>
     <version>3.5.6</version>
 </dependency>
 <!—引入适配Spring Framework的mybatis spring-->
 <dependency>
     <groupId>org.mybatis</groupId>
     <artifactId>mybatis-spring</artifactId>
     <version>2.0.6</version>
 </dependency>

第四步,添加乐观锁的拦截器,比如我在项目中使用如下代码。

代码语言:javascript复制
@Configuration
@MapperScan("com.alibaba.cloud.youxia.mapper")
public class MybatisPlusOptLockerConfig {
    /**
     * 1. 注入一个Mybatis Plus的拦截器MybatisPlusInterceptor,并绑定一个子拦截器。
          OptimisticLockerInnerInterceptor
     * 2. OptimisticLockerInnerInterceptor是用来实现乐观锁的核心类
     * @return
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        //1.新建一个拦截器对象MybatisPlusInterceptor
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //2.添加子拦截器OptimisticLockerInnerInterceptor
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        //3.返回给Spring Framework的IOC容器
        return interceptor;
    }

第五步,在实体类中添加version字段,比如我在项目中使用如下代码。

代码语言:javascript复制
@Data
@TableName(value = "user")
public class Example2ProductEntity implements Serializable {
    static final long serialVersionUID = -232434345545442L;
    /**
     * 1.乐观锁的版本号
     * 2.如果注释掉这一行代码,则乐观锁失效
     * 3.需要在数据库表中,添加一个version字段
    */
    @Version
    private Integer version;
}

完成上面五步,乐观锁就添加成功了,你就可以在业务服务中使用它了,关于乐观锁的原理,这里就不分析了。

当然如果还想提效,可以将乐观锁的拦截器,封装成一个Starter组件,这样业务都不用在每个服务中添加一遍了。

当然还可以提效,那就是下沉Dao层代码,这样业务服务几乎一行代码都不用改,就可以实现乐观锁,简单吧。

Spring Cloud Alibaba组合Mybatis-Plus真香

总结

咱们程序员在熟悉一个技术之前,一定要学会高效的去用,只有用了之后,才会去分析原理。

公众号初衷

知识输出是笔者的初衷,借助知识输出,能够认识更多的牛人,能够和牛人沟通,也是自己技术提升的一个机会。

0 人点赞