mybatis_plus的乐观锁

 乐观锁:总是假设最好的情况,每次读取数据时认为数据不会被修改(即不加锁),当进行更新操作时,会判断这条数据是否被修改,未被修改,则进行更新操作。若被修改,则数据更新失败,可以对数据进行重试(重新尝试修改数据)。

    悲观锁:总是假设最坏的情况,每次读取数据时认为数据会被修改(即加锁),当进行更新操作时,直接更新数据,结束操作后释放锁(此处才可以被其他线程读取)。

乐观锁、悲观锁使用场景?

  乐观锁一般用于读比较多的场合,尽量减少加锁的开销。

  悲观锁一般用于写比较多的场合,尽量减少 类似 乐观锁重试更新引起的性能开销。

乐观锁两种实现方式

方式一:通过版本号机制实现。

  在数据表中增加一个 version 字段。

  取数据时,获取该字段,更新时以该字段为条件进行处理(即set version = newVersion where version = oldVersion),若 version 相同,则更新成功(给新 version 赋一个值,一般加 1)。若 version 不同,则更新失败,可以重新尝试更新操作。

mybatis-plus 实现乐观锁(通过 version 机制)

实现思路:

  Step1:取出记录时,获取当前version

  Step2:更新时,带上这个version

  Step3:执行更新时, set version = newVersion where version = oldVersion

  Step4:如果version不对,就更新失败

mybatis-plus 代码实现乐观锁

Step1:

  配置乐观锁插件。

  编写一个配置类(可以与上例的分页插件共用一个配置类),将 OptimisticLockerInterceptor 通过 @Bean 交给 Spring 管理。

复制代码
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;

@Configuration
// 配置扫描mapper的路径
@MapperScan("com.mapper")
public class MyBatisPlusConfig {

    // 乐观锁插件
    //    @Bean
    //    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    //        return new OptimisticLockerInterceptor();
    //    }
}

Step2:

  定义一个数据库字段 version。

复制代码
CREATE TABLE test_mybatis_plus_user
(
    id BIGINT NOT NULL COMMENT '主键ID',
    name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
    age INT(11) NULL DEFAULT NULL COMMENT '年龄',
    email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
    create_time timestamp NULL DEFAULT NULL COMMENT '创建时间',
    update_time timestamp NULL DEFAULT NULL COMMENT '最后修改时间', 
    delete_flag tinyint(1) NULL DEFAULT NULL COMMENT '逻辑删除(0 未删除、1 删除)',
    version int NULL DEFAULT NULL COMMENT '版本号(用于乐观锁, 默认为 1)',
    PRIMARY KEY (id)
);

Step3:

  使用 @Version 注解标注对应的实体类。

  可以通过 @TableField 进行数据自动填充。

复制代码
/**
 * 版本号(用于乐观锁, 默认为 1)
 */
@Version
@TableField(fill = FieldFill.INSERT)
private Integer version;
 
 
@Override
public void insertFill(MetaObject metaObject) {
    this.strictInsertFill(metaObject, "version", Integer.class, 1);
}

package com.config;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        // 方法1:在3.3.0+版本可以使用strictInsertFill()、strictUpdateFill()方法
        // 方法2:通用的自动填充方法
        this.setFieldValByName("gmtCreate", new Date(), metaObject);
        this.setFieldValByName("gmtModified", new Date(), metaObject);
        this.setFieldValByName("version", 0, metaObject); //新增就设置版本值为0
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        // 这里只有为空才会填充数据 所以修改一下
        // 方法1:在3.3.0+版本可以使用strictUpdateFill()方法
        try {
            if (metaObject.hasSetter("gmtModified")) {
                metaObject.setValue("gmtModified", null);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 方法2:通用的自动填充方法
        this.setFieldValByName("gmtModified", new Date(), metaObject);
    }
}

Step4:

  简单测试一下,可以看一下 控制台 打印的 sql 语句。

复制代码
@Test
public void testVersion() {
    User user = new User();
    user.setName("tom").setAge(20).setEmail("tom@163.com");
    userService.save(user);
    userService.list().forEach(System.out::println);
    user.setName("jarry");
    userService.update(user, null);
    userService.list().forEach(System.out::println);
}
相关推荐
IT枫斗者枫哥12 小时前
MyBatis一对多分页:LIMIT 20,为什么凑不齐20个订单?
java·数据库
代码方舟12 小时前
Java数据工程:利用天远全网运营商三要素优化线上实名认证合规体验
java·人工智能
BBmmo12 小时前
我的 Java 学习笔记 · 第 7 篇:泛型与通配符
java
独泪了无痕12 小时前
Hutool之RandomUtil:随机数生成的终极利器
java·后端
花开路口12 小时前
深入理解 Java/Kotlin 协变与逆变
java·kotlin
运行时异常12 小时前
【WMS 仓储系统集成 AI Agent 实战】第 7 讲:Vue3 前端工程化——Token 刷新锁、Markdown 渲染踩坑与权限体系
java
她的男孩12 小时前
开放接口限流从 20 改到 200 还是每分钟 20 次:拆完防重放+幂等+限流,我找到 5 个静默失效的坑
java·后端·架构
Y0012 小时前
PostgreSQL 的锁:为什么你的 ALTER TABLE 会卡住,以及怎么查
数据库·postgresql
天天被压力13 小时前
【Python 量化取数指南 #13】Python 把行情落库:sqlite 一键存,回测随用随取
java·人工智能·python
天天被压力13 小时前
【Python 量化取数指南 #14】Python 清洗行情数据:复权停牌对齐,回测不翻车
java·人工智能·python