• 【MyBatis-Plus】DML


    👉 博客主页:准Java全栈开发工程师
    👉 00年出生,即将进入职场闯荡,目标赚钱,可能会有人觉得我格局小、觉得俗,但不得不承认这个世界已经不再是以一条线来分割的平面,而是围绕财富旋转的球面,成为有钱人不是为了去掌控球体的转向,而是当有人恶意掌控时,努力保护好家人和自己。

    一、id 生成策略

    • MP 提供了自动生成 id 的功能,也就是我们之前在测试添加功能时生成的那一大长串的数据。而对于不同的表,所生成的 id 策略也是不同的,那么我们该如何选择和设置 id 的生成策略呢?
    • 在该部分我们需要使用到一个新的注解 @TableId ,该注解用来设置 id 的生成策略,除了过时的策略外,还存在一些较为常用的策略,接下来一一对其进行介绍。

    在这里插入图片描述

    AUTO 策略

    AUTO 策略的作用是使用数据库 ID 自增,在使用该策略的时候一定要确保对应的数据库表设置了 ID主键自增,否则无效。

    INPUT 策略

    INPUT 策略为用户手工自定义 id ,使用该策略时需要取消掉数据库表中的自增属性,即取消勾选 id 自增勾选框,在添加数据时需要手动设置 id 值且必须设置,否则报错,不能成功完成添加操作。

    ASSIGN_ID 策略

    ASSIGN_ID 策略使用雪花算法生成 id ,这也是 MP 提供的默认的 id 策略,就是我们之前所看到的那一长串的 long 型数据,使用该策略可以不手动设置 id ,但是可以手动设置 id ,如果手动设置,则使用手动设置的 id ,不使用自动生成的。

    ASSIGN_UUID 策略

    使用 UUID 策略需要注意,主键的类型不能是 Long 类型,而应该改成 String 类型,与此同时,数据库表中主键类型设置为 varchar 类型,且长度要大于 32 ,因为 UUID 生成的主键为 32 位,如果长度小的话就会导致插入失败。

    二、简化配置

    • 对于每张表,如果都存在表名与实体类名不一致问题,即数据库表名为 “ tbl_user ”,实体类名为 “ user ”,我们岂不是每个类上都需要使用 @TableName 注解来手动完成表与实体类间的映射关系。
    • 且每张表都会涉及到 id 主键生成策略问题,如果使用同一个 id 生成策略,每个实体类上的 id 属性前都需要使用 @TableId 注解来指明 id 生成策略,这些代码显然都是重复的,对于这些重复的代码,我们可以将其配置在配置文件中,这样只需要在配置文件中配置一次,在其他地方就可以不再声明,简化配置。
    mybatis-plus:
      global-config:
        db-config:
          table-prefix: tbl_  # 设置表名前缀
          id-type: assign_id  # 设置 id 生成策略
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 进行了上述设置后,实体类上就无需使用 @TableName 注解指明对应的表名,也无需在使用 @TableId 注解指明 id 的生成策略。

    三、多记录操作

    删除多条数据

    • 使用 List 集合,将需要删除的数据 ID 添加进去,执行 deleteBatchIds 方法,将集合中存在的 ID 数据删除。
        @Test
        void testDeleteBatchIds(){
            ArrayList<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
            userMapper.deleteBatchIds(list);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    查询多条数据

    • 有根据 id 删除多条数据,自然也就有根据 id 查询多条数据,使用的方法也是非常相似的,均是 xxxBatchIds 。
        @Test
        void testDeleteBatchIds(){
            ArrayList<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
            userMapper.selectBatchIds(list);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    四、逻辑删除

    • “程序员删库跑路”这个话题一直是程序员广泛使用的梗,这也体现出了一个问题,在工作过程中,不要随便删除数据,如果有这方面的需求,一般都会采用假删除来实现。
    • 那如何才能实现假删除也就是逻辑删除呢?

    步骤一:数据库表添加 deleted 列

    表中新增一列,用于表示该数据是否被逻辑删除了。一般会命名为 deleted ,可根据开发实际要求进行命名,类型为 int 类型,通常 1 代表删除,0 代表未删除。

    步骤二:实体类添加 deleted 属性

    实体类需要与表进行对应,所以,当表中添加了某个字段后,实体类相应的也需要添加字段,保持一致。同时使用 @TableLogic 注解指明该字段为逻辑删除字段,value 为正常数据的值,delval 为删除数据的值。

        @TableLogic(value = "0",delval = "1")
        private Integer deleted;
    
    • 1
    • 2
    • 当设置了逻辑删除字段后,在此执行删除方法时执行的就不再是 delete 语句,而变为了 update 语句。

    测试删除操作

        @Test
        void testDeleteById(){
            int i = userMapper.deleteById(4L);
            System.out.println(i);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 仔细观察执行的 SQL 语句,是不是执行的 update 语句呢?
      在这里插入图片描述

    配置文件配置相关内容

    • 通常情况下,我们逻辑删除的字段名以及删除规范都是一致的,在每个实体类中书写相同的内容不免会觉得有些麻烦,所以将这些内容配置在配置文件中,简化开发。
    mybatis-plus:
      global-config:
          logic-delete-field: deleted # 指明逻辑删除字段名
          logic-delete-value: 1       # 删除数据值
          logic-not-delete-value: 0   # 正常数据值
    
    • 1
    • 2
    • 3
    • 4
    • 5

    五、乐观锁

    1、乐观锁的实现方式

    • 数据库表中添加 version 列,比如默认值给 1 。
    • 第一个线程要修改数据之前,取出记录时,获取当前数据库中的 version = 1 。
    • 第二个线程要修改数据之前,取出记录时,获取当前数据库中的 version = 1 。
    • 第一个线程执行时,会更新 version 值。
      • newVersion = version+1,更新后 version 值为 2。
    • 第二个线程执行时,也会更新 version 值。
      • newVersion = version+1,更新后 version 值为 2。
    • 假如这两个线程都来更新数据,第一个和第二个线程都可能先执行,当第一个线程先执行时,会把 version 改为 2 ,第二个线程再执行时,此时数据库表的 version 数据值已经为 2 了,不满足 where version = 1 的条件,所以第二个线程会执行失败。
    • 假如第二个线程先执行,会把 version 改为 2 ,第一个线程再执行时,此时数据库表中的 version 数据值已经变为了 2 ,所以第一个线程会执行失败。
    • 这样就保证了不管谁先执行都只能有一个线程执行成功,这就是 MP 提供的乐观锁的实现原理分析。
    • 使用锁能够解决线程并发问题,如果不理解为什么要使用锁,可以代入卖票的场景,一共有 100 张票,当只剩下最后 1 张票的时候,有很多人在不同的窗口同时买,如果不使用锁来实现,可能会出现第 0 张票,甚至第 -1 张票的场景,这是我们不想出现的,这也就是为什么要使用乐观锁的原因,就是为了防止这种并发情况出现。

    2、实现步骤

    1)数据库表添加列

    新增一个字段列,命名可以为 version ,也可以为其它命名,只是一个名称而已,类型为 int 类型。

    2)实体类添加对应的属性
        @Version
        private Integer version;
    
    • 1
    • 2
    3)添加乐观锁拦截器
    @Configuration
    public class MpConfig {
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor(){
            // 先创建 MP 的拦截器
            MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
            // 添加乐观锁拦截器
            mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
            return mpInterceptor;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    4)测试
    • 要想实现乐观锁,首先第一步应该是拿到表中的 version,然后拿 version 当条件,再将 version
      加 1 更新回到数据库表中。
        @Test
        void testLock(){
            //1.先通过要修改的数据 id 将当前数据的 version 查询出来,查询出来的 user 中肯定携带有 version 数据
            User user = userMapper.selectById(4L);
            //2.修改属性
            user.setUsername("origin6666");
            userMapper.updateById(user);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    • 重新回到数据库查询 id 为 4 的数据,发现 version 已经更新为了 2。
      在这里插入图片描述
    5)模拟多线程
    • 让两个线程同时进行操作 id 为 4 的数据,给其更改 username 字段,根据代码显示,会优先执行user2 的操作,观察最后数据库结果,此时的 version 值为 4 。
        @Test
        void testLock(){
            User user = userMapper.selectById(4L);
            User user2 = userMapper.selectById(4L);
            user.setUsername("og6666");
            user2.setUsername("og8888");
            userMapper.updateById(user2);
            userMapper.updateById(user);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 显示第一个 update 操作执行成功,第二个执行失败,符合预期。

    在这里插入图片描述

    • 数据库表中的信息也成功该为 user2 设置的名称,version 值也修改为 5 。

    在这里插入图片描述

    👉 以上就是文章的全部内容啦,诸佬如果有任何建议都可以提哦。
    👉 创作不易,如果觉得对您有帮助的话,欢迎关注✨点赞👍收藏📂哦。

  • 相关阅读:
    java.lang.instrument.Instrumentation文档翻译
    H3C的IRF堆叠互联关系说明
    C++11绑定器bind及function机制
    【redis-06】redis进阶知识点-订阅、主从、哨兵、缓存穿透击穿和雪崩
    表情和微表情数据集总结
    2022年最新Python大数据之Python基础【九】面向对象与继承
    java计算机毕业设计销售管理系统演示录像源程序+mysql+系统+lw文档+远程调试
    eProsima-fastdds简介
    RK3568+Codesys ARM+LINUX硬件平台的软PLC解决方案
    Fabric.js 复制粘贴元素
  • 原文地址:https://blog.csdn.net/Coder_Farmer/article/details/125523398