前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MyBatis-Plus 乐观锁 防止超卖、逻辑删除、自动填充、Id自增

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

作者头像
宁在春
发布2022-10-31 14:01:10
8800
发布2022-10-31 14:01:10
举报
文章被收录于专栏:关于Java学习@宁在春

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

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

介绍

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

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

  1. 乐观锁: 主要用于防止商品超卖的方面
  2. 逻辑删除: 逻辑删除主要是用于用户对于数据的误删的一种撤销机制。 删除分为两种
    • 一种是物理删除 就是数据库层面的删除 彻底的从磁盘中删除
    • 另外一种就是今天讲的 逻辑删除 删除后还是会在数据库里保存着 只是查询的时候 需要带上参数才能查到
    • 当然彻底删除的时候也是需要带上那个参数才能彻底删除的。
  3. 自动填充:
    • 我之前看阿里的那个规范的时候 有看到就是说在数据库里面建立每一张表 都需要有创建时间和修改时间
    • 所以MP就提供自动填充的功能,帮助自定设置这些字段的值,提升开发效率,代码也会显得特别优雅。

乐观锁

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

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

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

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

使用方法

字段上加上@Version注解

代码语言:javascript
复制
@Version
private Integer version;

mybatis配置注入下面这个bean

代码语言:javascript
复制
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }

环境搭建 :

代码语言:javascript
复制
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层

代码语言:javascript
复制
@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层

代码语言:javascript
复制
public interface UserMapper extends BaseMapper<User> {

}

MyBatisPlusConfig

代码语言:javascript
复制
@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

代码语言:javascript
复制
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

乐观锁测试

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

代码语言:javascript
复制
    @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)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1PiN6HBX-1618399940155)(mybatis-plus.assets/image-20210414190927238.png)]

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

代码语言:javascript
复制
    @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)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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 加入下面配置
代码语言:javascript
复制
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注解
代码语言:javascript
复制
@TableLogic
private Integer deleted;	

逻辑删除 测试

代码语言:javascript
复制
// 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)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xFtrX2OJ-1618399940160)(mybatis-plus.assets/image-20210414191803396.png)]

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

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

自动填充

原理:

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

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

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

}

自定义实现类 MyMetaObjectHandler

代码语言:javascript
复制
@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(不含中划线)

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

代码语言:javascript
复制
//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)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Wb0CIUf-1618399940166)(mybatis-plus.assets/image-20210414192953564.png)]

搞定

溜了溜了

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

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-04-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • MyBatis-Plus 乐观锁 防止超卖、逻辑删除、自动填充 Day3
    • 介绍
      • 乐观锁
        • 使用方法
        • 环境搭建 :
        • 乐观锁测试
      • 逻辑删除
        • 使用方法:
        • 逻辑删除 测试
      • 自动填充
        • 原理:
        • 测试
      • 搞定
      相关产品与服务
      数据库
      云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档