MyBatis-Plus 乐观锁 防止超卖、逻辑删除、自动填充、Id自增

MyBatis-Plus 乐观锁 防止超卖、逻辑删除、自动填充 Day3

前面的简单的讲了一下mybatis-plus的使用 当然有很多不足 我写博客就是想促进大家一起学习 也想让这些内容更简单一些。

介绍

这次就主要讲乐观锁、逻辑删除、自动填充。这几项在项目是用的非常多的。

先讲一下主要应用 之后再讲理论和实现。

  1. 乐观锁:

    主要用于防止商品超卖的方面

  2. 逻辑删除:

    逻辑删除主要是用于用户对于数据的误删的一种撤销机制。

    删除分为两种

    • 一种是物理删除 就是数据库层面的删除 彻底的从磁盘中删除
    • 另外一种就是今天讲的 逻辑删除 删除后还是会在数据库里保存着 只是查询的时候 需要带上参数才能查到
    • 当然彻底删除的时候也是需要带上那个参数才能彻底删除的。
  3. 自动填充:

    • 我之前看阿里的那个规范的时候 有看到就是说在数据库里面建立每一张表 都需要有创建时间和修改时间

    • 所以MP就提供自动填充的功能,帮助自定设置这些字段的值,提升开发效率,代码也会显得特别优雅。

乐观锁

当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

能够保证数据的安全性和一致性。

因为后面还有逻辑删除、自动填充 环境就全部搭好拉。

使用方法

字段上加上@Version注解

@Version
private Integer version;

mybatis配置注入下面这个bean

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }

环境搭建 :

  • DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user`  (
      `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
      `name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '姓名',
      `age` int(11) NULL DEFAULT NULL COMMENT '年龄',
      `email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱',
      `version` int(10) NULL DEFAULT 1 COMMENT '乐观锁',
      `deleted` int(10) NULL DEFAULT 0 COMMENT '逻辑删除',
      `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
      `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 1337575143814062086 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
  • 要导入的依赖 这里就不说了 我之前的博客也有。

  • user层

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Accessors(chain = true)
    @TableName(value = "user")
    public class User {
        @TableId(type = IdType.AUTO)
        private Long id;
        private String name;
        private Integer age;
        private String email;
    
        @Version  // 这里是乐观锁的注解
        private Integer version;
    
        @TableLogic  // 这是逻辑删除的注解
        private Integer deleted;
    
        @TableField(fill = FieldFill.INSERT)  //这里是自动填充的注解
        private Date createTime;
    
        @TableField(fill = FieldFill.INSERT_UPDATE)
        private Date updateTime;
    }
    
  • mapper层

    public interface UserMapper extends BaseMapper<User> {
    
    }
    
  • MyBatisPlusConfig

    @Configuration
    public class MybatisPlusConfig {
    
        // 分页
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
            // 这里是注册分页插件
            mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
            // 注册乐观锁 插件
            mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
            return mybatisPlusInterceptor;
        }    
    }
    
  • yaml

    server:
      port: 8484
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        username: root
        password: 123456
        url: jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=UTC&useSSL=false&characterEncoding=utf8&serverTimezone=GMT
    
    

乐观锁测试

先测试一下 没有加乐观锁的 会是什么样

    @Test
    public  void updateOptimisticLockerInterceptor(){
        //A 线程
        User user = userMapper.selectById(102L);
        user.setName("点赞1");
        user.setAge(3);
        //B 线程  模拟另外一个线程插队
        User user1 = userMapper.selectById(102L);
        user1.setName("收藏加三连");
        user1.setAge(4);
        userMapper.updateById(user1);
        // 自旋锁来尝试多次提交
        userMapper.updateById(user);  // 如果没有乐观锁 就会覆盖插队的值
    }

下面给大家看一下控制台的输出

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1PiN6HBX-1618399940155)(mybatis-plus.assets/image-20210414190927238.png)]

为了方便观看 我把测试数据改了 来接着看一下这次的结果

    @Test
    public  void updateOptimisticLockerInterceptor(){
        //A 线程
        User user = userMapper.selectById(102L);
        user.setName("关注宁在春");
        user.setAge(3);
        //B 线程  模拟另外一个线程插队
        User user1 = userMapper.selectById(102L);
        user1.setName("给宁在春点赞");
        user1.setAge(4);
        userMapper.updateById(user1);
        // 自旋锁来尝试多次提交
        userMapper.updateById(user);  // 如果没有乐观锁 就会覆盖插队的值
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6iRJXShb-1618399940158)(mybatis-plus.assets/image-20210414191159384.png)]

这就是加了乐观锁的作用 在多线程下 可以保证数据的安全 防止商品超卖等等。

逻辑删除

只对自动注入的sql起效:

  • 插入: 不作限制
  • 查找: 追加where条件过滤掉已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段
  • 更新: 追加where条件防止更新到已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段
  • 删除: 转变为 更新

例如:

  • 删除: update user set deleted=1 where id = 1 and deleted=0
  • 查找: select id,name,deleted from user where deleted=0

使用方法:

步骤1: 配置
  • 在application.yml 加入下面配置
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: flag  # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
步骤2: 实体类字段上加上@TableLogic注解
@TableLogic
private Integer deleted;	

逻辑删除 测试

// TODO tableLogic 逻辑删除
@Test
public void tableLogic(){
    userMapper.deleteById(103);
    List<User> userList = userMapper.selectList(null);
    userList.forEach(System.out::println);
}

测试结果如下 使用查询全部方法 明显查不到这行数据拉 我们接下来看看 数据库里的表 看还有没有

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xFtrX2OJ-1618399940160)(mybatis-plus.assets/image-20210414191803396.png)]

数据库里面还存在 只是deleted 变成1拉

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CwM0ABEf-1618399940164)(mybatis-plus.assets/image-20210414191941544.png)]

自动填充

原理:

  • 实现元对象处理器接口:com.baomidou.mybatisplus.core.handlers.MetaObjectHandler
  • 注解填充字段 @TableField(.. fill = FieldFill.INSERT) 生成器策略部分也可以配置!
public class User {

    // 注意!这里需要标记为填充字段
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

}
  • 自定义实现类 MyMetaObjectHandler

    @Slf4j
    @Component
    public class MyMetaObjectHandler implements MetaObjectHandler {
    
        @Override
        public void insertFill(MetaObject metaObject) {
            log.info("start insert fill ....");
            this.setFieldValByName("createTime",new Date(),metaObject);
            this.setFieldValByName("updateTime",new Date(),metaObject);
        }
    
        @Override
        public void updateFill(MetaObject metaObject) {
            log.info("start update fill ....");
            this.setFieldValByName("updateTime",new Date(),metaObject);
        }
    }
    

测试

我们来增加一行数据看一看会不会吧 这里把Id 自增也讲一起讲了吧

mybatisplus 默认的主键自增 是默认使用雪花算法+UUID(不含中划线)

具体的 大家可以自行研究。

//TODO insert 配置了自动填充后的insert
@Test
public void insert() {
    User user = new User().setName("自动填充").setAge(99).setEmail("ssss@qq.com");
    int i = userMapper.insert(user);
    System.out.println(i);
    Map<String, Object> map = new HashMap<String,Object>();
    map.put("name","自动填充");
    List<User> users = userMapper.selectByMap(map);
    users.forEach(System.out::println);
}

测试图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Wb0CIUf-1618399940166)(mybatis-plus.assets/image-20210414192953564.png)]

搞定

溜了溜了

大家看的好 就评论评论 一起学习学习咯

刚开始 文笔不咋好 争取之后 我加油写的好一些 再来点故事。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值