MyBatis-Plus高级扩展详解

 更新时间:2025年03月11日 10:10:47   作者:一个懵懂的菜鸟  
本文介绍了MyBatis-Plus中逻辑删除和乐观锁的实现概念、方法和示例,逻辑删除通过更改记录状态模拟删除,而乐观锁通过版本号或时间戳确保并发操作的正确性

MyBatis-Plus高级扩展

逻辑删除实现

概念:

逻辑删除,可以方便地实现对数据库记录的逻辑删除而不是物理删除。逻辑删除是指通过更改记录的状态或添加标记字段来模拟删除操作,从而保留了删除前的数据,便于后续的数据分析和恢复。

  • 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
  • 逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录

逻辑删除实现:

  • 数据库和实体类添加逻辑删除字段
  • 表添加逻辑删除字段可以是一个布尔类型、整数类型或枚举类型。
ALTER TABLE USER ADD deleted INT DEFAULT 0 ;  # int 类型 1 逻辑删除 0 未逻辑删除
  • 实体类添加逻辑删除属性
@Data
public class User {

   // @TableId
    private Integer id;
    private String name;
    private Integer age;
    private String email;
    
    @TableLogic
    //逻辑删除字段 int mybatis-plus下,默认 逻辑删除值为1 未逻辑删除 0 
    private Integer deleted;
}
  • 指定逻辑删除字段和属性值

单一指定

@Data
public class User {

   // @TableId
    private Integer id;
    private String name;
    private Integer age;
    private String email;
     @TableLogic
    //逻辑删除字段 int mybatis-plus下,默认 逻辑删除值为1 未逻辑删除 1 
    private Integer deleted;
}

全局指定

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
  • 演示逻辑删除操作

逻辑删除以后,没有真正的删除语句,删除改为修改语句!删除代码:

//逻辑删除
@Test
public void testQuick5(){
    //逻辑删除
    userMapper.deleteById(5);
}

执行效果:

JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5871a482] will not be managed by Spring ==> Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0 ==> Parameters: 5(Integer) <== Updates: 1

  • 测试查询数据
@Test
public void testQuick6(){
    //正常查询.默认查询非逻辑删除数据
    userMapper.selectList(null);
}

//SELECT id,name,age,email,deleted FROM user WHERE deleted=0

乐观锁实现

悲观锁和乐观锁场景和介绍

并发问题场景演示:

**解决思路: **

乐观锁和悲观锁是在并发编程中用于处理并发访问和资源竞争的两种不同的锁机制!!

悲观锁:

  • 悲观锁的基本思想是,在整个数据访问过程中,将共享资源锁定,以确保其他线程或进程不能同时访问和修改该资源。悲观锁的核心思想是"先保护,再修改"。
  • 在悲观锁的应用中,线程在访问共享资源之前会获取到锁,并在整个操作过程中保持锁的状态,阻塞其他线程的访问。
  • 只有当前线程完成操作后,才会释放锁,让其他线程继续操作资源。
  • 这种锁机制可以确保资源独占性和数据的一致性,但是在高并发环境下,悲观锁的效率相对较低。

乐观锁:

  • 乐观锁的基本思想是,认为并发冲突的概率较低,因此不需要提前加锁,而是在数据更新阶段进行冲突检测和处理。乐观锁的核心思想是"先修改,后校验"。
  • 在乐观锁的应用中,线程在读取共享资源时不会加锁,而是记录特定的版本信息。
  • 当线程准备更新资源时,会先检查该资源的版本信息是否与之前读取的版本信息一致,如果一致则执行更新操作,否则说明有其他线程修改了该资源,需要进行相应的冲突处理。
  • 乐观锁通过避免加锁操作,提高了系统的并发性能和吞吐量,但是在并发冲突较为频繁的情况下,乐观锁会导致较多的冲突处理和重试操作。

理解点:悲观锁和乐观锁是两种解决并发数据问题的思路,不是具体技术!!!

具体技术和方案:

(1)乐观锁实现方案和技术:

  • 版本号/时间戳:为数据添加一个版本号或时间戳字段,每次更新数据时,比较当前版本号或时间戳与期望值是否一致,若一致则更新成功,否则表示数据已被修改,需要进行冲突处理。
  • CAS(Compare-and-Swap):使用原子操作比较当前值与旧值是否一致,若一致则进行更新操作,否则重新尝试。
  • 无锁数据结构:采用无锁数据结构,如无锁队列、无锁哈希表等,通过使用原子操作实现并发安全。

(2)悲观锁实现方案和技术:

  • 锁机制:使用传统的锁机制,如互斥锁(Mutex Lock)或读写锁(Read-Write Lock)来保证对共享资源的独占访问。
  • 数据库锁:在数据库层面使用行级锁或表级锁来控制并发访问。
  • 信号量(Semaphore):使用信号量来限制对资源的并发访问。

介绍版本号乐观锁技术的实现流程:

  • 每条数据添加一个版本号字段version
  • 取出记录时,获取当前 version
  • 更新时,检查获取版本号是不是数据库当前最新版本号
  • 如果是[证明没有人修改数据], 执行更新, set 数据更新 , version = version+ 1
  • 如果 version 不对[证明有人已经修改了],我们现在的其他记录就是失效数据!就更新失败

使用mybatis-plus数据使用乐观锁

  • 添加版本号更新插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
    return interceptor;
}
  • 乐观锁字段添加@Version注解。注意:数据库也需要添加version字段
ALTER TABLE USER ADD VERSION INT DEFAULT 1 ;  # int 类型 乐观锁字段
  • 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
  • 仅支持 updateById(id) 与 update(entity, wrapper) 方法
@Version
private Integer version;
  • 正常更新使用即可
//演示乐观锁生效场景
@Test
public void testQuick7(){
    //步骤1: 先查询,在更新 获取version数据
    //同时查询两条,但是version唯一,最后更新的失败
    User user  = userMapper.selectById(5);
    User user1  = userMapper.selectById(5);

    user.setAge(20);
    user1.setAge(30);

    userMapper.updateById(user);
    //乐观锁生效,失败!
    userMapper.updateById(user1);
}

防全表更新和删除实现

针对 update 和 delete 语句 作用:阻止恶意的全表更新删除

  • 添加防止全表更新和删除拦截器
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
  MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
  return interceptor;
}
}
  • 测试全部更新或者删除
@Test
public void testQuick8(){
    User user = new User();
    user.setName("custom_name");
    user.setEmail("xxx@mail.com");
    //Caused by: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Prohibition of table update operation
    //全局更新,报错
    userService.saveOrUpdate(user,null);
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • java中继承测试代码分析

    java中继承测试代码分析

    这篇文章主要介绍了java中继承测试代码分析,具有一定借鉴价值,需要的朋友可以参考下。
    2017-12-12
  • 深入理解Java设计模式之策略模式

    深入理解Java设计模式之策略模式

    这篇文章主要介绍了JAVA设计模式之策略模式的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下
    2021-11-11
  • 最新IntelliJ IDEA 2021版配置 Tomcat 8.5 的详细步骤

    最新IntelliJ IDEA 2021版配置 Tomcat 8.5 的详细步骤

    idea开发工具一直是java环境最好用,很受广大开发者喜爱,今天通过本文给大家分享最新IntelliJ IDEA 2021版配置 Tomcat 8.5 的详细步骤,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友可以参考下
    2021-06-06
  • IntelliJ IDEA 2021.1 EAP 1 发布支持 Java 16 和 WSL 2

    IntelliJ IDEA 2021.1 EAP 1 发布支持 Java 16 和 WSL 2

    这篇文章主要介绍了IntelliJ IDEA 2021.1 EAP 1 发布支持 Java 16 和 WSL 2,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02
  • Java常用工具类总结

    Java常用工具类总结

    今天带大家学习Java常用工具类,文中有非常详细的图文解说及代码示例,对正在学习java的小伙伴们很有帮助,需要的朋友可以参考下
    2021-05-05
  • Java编程实现汉字按字母顺序排序的方法示例

    Java编程实现汉字按字母顺序排序的方法示例

    这篇文章主要介绍了Java编程实现汉字按字母顺序排序的方法,结合具体实例形式分析了java编码转换及字母排序相关操作技巧,需要的朋友可以参考下
    2017-07-07
  • SpringBoot+Ajax+redis实现隐藏重要接口地址的方法

    SpringBoot+Ajax+redis实现隐藏重要接口地址的方法

    这篇文章主要介绍了SpringBoot+Ajax+redis实现隐藏重要接口地址,本篇文章主要讲诉使用SpringBoot项目配合Ajax和redis实现隐藏重要接口地址,这里我以隐藏秒杀地址为例,需要的朋友可以参考下
    2024-03-03
  • mybatisplus添加真正的批量新增、批量更新的实现

    mybatisplus添加真正的批量新增、批量更新的实现

    这篇文章主要介绍了mybatisplus添加真正的批量新增、批量更新的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • springboot项目中统一时间格式处理方法

    springboot项目中统一时间格式处理方法

    JacksonConfiguration主要用于配置JSON的序列化和反序列化,而LocalDateTimeFormatter则用于处理请求和响应中的LocalDateTime格式,这两个配置项在SpringBoot项目中至关重要,确保数据格式的正确处理和传输
    2024-10-10
  • MybatisPlus BaseMapper 中的方法全部 Invalid bound statement (not found Error处理)

    MybatisPlus BaseMapper 中的方法全部 Invalid bound statement (not f

    这篇文章主要介绍了MybatisPlus BaseMapper 中的方法全部 Invalid bound statement (not found)的Error处理方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09

最新评论