MyBatis-Plus的一些高级干货

MyBatis-Plus的一些高级干货

MyBatis Plus(简称 MP)是一个 MyBatis 的增强版,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

记住:MyBatis\color{red}{对MyBatis 只做增强不做改变,引入它不会对现有工程产生影响}

mp官方文档:https://mp.baomidou.com/guide/

1.MyBatis-Plus与MyBatis的区别

  1. 对于实体类而言,需要加一定的注解。
  2. MyBatis-Plus通过@TableName\color{blue}{@TableName}让实体类名与表名关联,@TableField\color{blue}{@TableField}与表字段关联。
  3. 通用性不同,MyBatis是外国人开发的,国内外皆通用,而MyBatis-Plus是由国内人士自发组织的开源,目前主要通用于国内;
  4. MyBatisPlusibatismybatis\color{green}{MyBatisPlus属于第三方扩展,学习一般都是学习基础,比如ibatis或者mybatis}\color{green}{而扩展是第三方提供的更高级面向开放的支持,这两者不能作为比较。}

注意:mybatis-plus会自动维护mybatis以及mybatis-spring的依赖,所以不需要引入后两者,避免发生版本冲突. 只需把mybatis的依赖换成mybatis-plus的依赖。

2.全局唯一id的生成

Mybatis plus 在调用插入方法时,会自动生成id,是一个全局唯一id,一起插入到数据表中。

mp默认新增的时候,产生的是全局唯一id,采用雪花算法生成,自3.3.0开始,默认使用雪花算法+UUID。(Twitter的snowflake算法又名雪花算法,生成long类型的唯一数字)

如图:

在这里插入图片描述
而这个唯一id的生成,常常用来做我们的数据库字段的主键~!

3.主键生成策略:

在日常开发中,对于一些数据库中的主键,我们一般会采用 idUUIDrediszookeeper\color{#4285f4}{自增id,}\color{#ea4335}{UUID,}\color{#fbbc05}{雪花算法,}\color{#4285f4}{redis生成,}\color{#34a853}{zookeeper生成}\color{#ea4335}{} 等方式,

具体对比:分布式系统唯一ID生成方案

mp自3.3.0开始,默认使用雪花算法+UUID(不含中划线)。
主键生成策略必须使用INPUT。

设置生成的主键是自增样式:

(在mp生成id时,根据上一个id的数值,而自增)

实现过程:

3.1实体类上添加注解:

@TableId(type = IdType.INPUT) 
private Long id;

如图:
在这里插入图片描述

3.2数据库字段设置为自增

在这里插入图片描述

结果:
在这里插入图片描述

Mp中其他的id属性的解释:
在这里插入图片描述
一旦手动输入id之后,就需要自己配置id生成方法了!不然就可以用这些注解来生成id自动填入数据库。

4.自动填充:

开发中,一般数据库总有一些字段我们想要的是\color{red}{不需要修改,自动生成的}。比如创建时间,修改时间等字段!这些个操作一般都是自动化完成的,企业级都不希望手动更新。

(在阿里巴巴开发手册中就有写:所有的数据库表gmt_create,gmt_modified 字段几乎都要有,而自动化填入,便于追踪)

实现方式

4.1 方式一:数据库级别 (工作中不建议)

  1. 比如在表中新增字段create_time, update_time。只需要设置默认的填充方式即可。
    在这里插入图片描述

结果:
在这里插入图片描述

4.2 方法二:代码级别 (推荐)

  1. 删除数据库的该字段的默认值,更新操作等设置(上一种方式我设置了,我恢复一下而已)。
    (恢复如图下这样)
    在这里插入图片描述

  2. 添加注解
    实体类上加个注解,一个是新增,一个是更新。

    // 设置填充字段的填充类型
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    
  3. 编写处理器来处理这个注解,自定义实现类来实现implements MetaObjectHandler()

    配置类源码如下:

    @Slf4j
    @Component   // 一定不要忘记把处理器加入到IOC容器中。
    public class MyMetaObjectHandler implements MetaObjectHandler {
    
    // 插入时候的填充策略
    	@Override
        public void insertFill(MetaObject metaObject) {
            log.info("start insert fill ....");
            this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); //版本 3.3.0(推荐使用)
                       }
    // 更新时间的填充策略
        @Override
        public void updateFill(MetaObject metaObject) {
            log.info("start update fill ....");
            this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
    	}
    }
    

程序会通过反射去读取实体类中对应的注解,填入内容。

注意事项:
• 字段必须声明TableField注解,属性fill选择对应策略,该声明告知MybatisPlus需要预留注入SQL字段。
• 填充处理器MyMetaObjectHandler在SpringBoot中需要声明@Component注解或@Bean注入。

填充失效问题解决
把date 改为了LocalDateTime 类型,依然对应的是SQL中的datetiem或date类型。

结果:

  @Test
    public void testInsert(){
        User user =new User();
        user.setAge(23);
        int result = userMapper.insert(user); //自动生成id
        System.out.println(result);
    }

当执行插入或者更新操作时候,自动修改值。
在这里插入图片描述

5. 乐观锁:

\color{red}{乐观锁:}顾名思义十分乐观,它总是认为程序不会出现问题,无论干什么都不去上锁!如果出了问题,就在测试加锁处理,再次更新值测试。

\color{red}{悲观锁:}顾名思义十分悲观,它总是认为程序会出现问题,无论干什么都去上锁!再去操作。

乐观锁原理机制:Versionnewversion\color{blue}{有一个Version字段 ,每次会new version ,每次操作都带有一个版本号,来相互验证。}

乐观锁实现方式:

  • 后端取记录数据时,先查询获取当前version版本。
  • 更新时,带上这个version
  • 执行更新时,set version = newVersion where version = oldVersion
  • 如果version不对,就不允许更新,失败操作。

主要适用场景:当要更新一条记录的时候,希望这条记录没有被别人更新。

5.1实现过程:

  1. 在数据库表中添加版本字段,version int ,设置默认值1.
    在这里插入图片描述

  2. 实体类添加版本注解:

    @Version  //乐观锁注解
    private Integer version;
    

注解 @Version 必须有!

  1. 自定义一个配置类mpConfig:
    标识为mybatis配置类,注册乐观锁插件即可,

    源码如下:

    package com.zout.mapper;
    /**
     * @Description:
     * @Author: Zoutao
     * @Date: 2020/5/16
     */
    
    import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    @EnableTransactionManagement
    @Configuration  //标示为mybatis配置类
    public class mpConfig {
        // 注册乐观锁插件
        @Bean
        public OptimisticLockerInterceptor optimisticLockerInterceptor() {
            return new OptimisticLockerInterceptor();
        }
    }
    

如图:

在这里插入图片描述

  1. 测试方法:
    // 测试乐观锁 >>单线程时,方法可行
    @Test
    public void testInterceptor(){
        // 1.查询用户信息
        User user = userMapper.selectById(4L); 
        // 2.修改用户信息
        user.setName("王五");
        user.setAge(500);
        user.setEmail("[email protected]");
        // 3. 执行更新操作
        int result = userMapper.updateById(user); 
        System.out.println(result);
    }

过程剖析:
首先查询version=1,然后更新以后,version=2了。

单线程下:
在这里插入图片描述

对应SQL原理

update user set name = '王五',version = 2 where id = 100 and version = 1

结果,版本正常,更新成功。

多线程下:

    // 测试乐观锁 >> 多线程下,发现方法不可行
    @Test
    public void testInterceptor2(){
        // 模拟线程1
        User user1 = userMapper.selectById(4L);
        user1.setName("陈二");
        user1.setAge(500);
        // 模拟线程2,执行插队操作。跟线程1互相抢夺
        User user2 = userMapper.selectById(4L);
        user2.setName("王二麻子");
        user2.setAge(800);
        userMapper.updateById(user2); // 模拟线程2抢先操作
        // 执行更新操作
        userMapper.updateById(user1); //如果没有乐观锁,就会覆盖插队线程2的值。有乐观锁,则更新失败。
    }

发现两个线程都拿到了版本2,加锁。

在这里插入图片描述

最后,因为我们有乐观锁存在,所以线程2的更新操作成功了,而线程1的更新则失败了,被限制。

在这里插入图片描述
可以尝试自旋锁来尝试多次提交,依然可以避免同时被改写的问题。

6. 逻辑删除

  • 物理删除:从数据库直接删除数据。
  • \color{green}{逻辑删除}:在数据库中没有直接删除,而是通过一个变量让它失效,依旧保存在数据库中,只是不显示了。

应用场景:

  • 管理员可以查看被删除的记录,普通用户删除后,数据消失!这样做是防止数据的丢失,类似于回收站功能。

6.1实现过程:

  1. 比如在数据库表中新增一个字段 deleted。
    在这里插入图片描述
    当(deleted=0 >> deleted=1 )时,表示该数据被删除了。

  2. 实体类字段上加上@TableLogic注解

    @TableLogic
    private Integer deleted;
    

说明:
• 字段支持所有数据类型(推荐使用 Integer,Boolean,LocalDateTime)
• 如果使用LocalDateTime,建议逻辑未删除值设置为字符串null,逻辑删除值只支持数据库函数例如now()

  1. 全局配置-全局逻辑删除(非必须)
    mp,3.1.1版本以上使用,0未删除,1已删除。

    #全局逻辑删除字段值
    mybatis-plus.global-config.db-config.logic-delete-field: flag
    # 逻辑已删除值(默认为 1)
    mybatis-plus.global-config.db-config.logic-delete-value: 1
    # 逻辑未删除值(默认为 0)
    mybatis-plus.global-config.db-config.logic-not-delete-value: 0
    

如图:
在这里插入图片描述
注意:

使用此配置则不需要在实体类上添加 @TableLogic。
但如果实体类上有 @TableLogic 则以实体上的为准,忽略这个全局配置。( 即先查找注解再查找全局,都没有则此表没有逻辑删除。)

  1. 测试方法:
    //删除-逻辑删除
    @Test
    public void testDelById(){
        userMapper.deleteById(5L);
    }

原理:>>>\color{blue}{逻辑删除 >>>调用的是删除方法,但实际执行的是一个更新操作。 }
在这里插入图片描述

效果:

在这里插入图片描述

使用mp自带方法删除和查找都会附带逻辑删除功能 (自己写的xml不会)
删除:update user set deleted=1 where id =1 and deleted=0
查找:select * from user where deleted=0

再查询数据时:会自动加入逻辑未删除的标志语句来查。(自己写的SQL则加上这个条件即可。)
如图:
在这里插入图片描述
记录依旧存在数据库,但是值已经改变了,所以普通用户查寻不到,admin可以。

7. 性能分析-执行 SQL 分析打印

在平时的开发中,会遇到一些慢SQL,一般是进行测试,druid监控等来找谁慢。MP提供自有插件来分析慢SQL ,如果超过设定时间,就停止运行。

(该插件 MP3.2.0 以上版本移除推荐使用第三方扩展p6spy ,执行SQL分析打印功能)

该功能依赖 p6spy 组件,完美的输出打印 SQL 及执行时长 ,MP 3.1.0 以上版本使用。

p6spy 依赖引入:

<!-- https://mvnrepository.com/artifact/p6spy/p6spy -->
<dependency>
    <groupId>p6spy</groupId>
    <artifactId>p6spy</artifactId>
    <version>3.8.7</version>
</dependency>

作用:用于输出每条 SQL 语句及其执行时间。

效果:SQL会格式化,且出现执行时间,如果超过指定时间,会提醒报错,自己修改优化SQL即可。

在这里插入图片描述

注意:该插件有性能损耗,不建议生产环境使用,在springboot配置环境为dev或者test环境下使用就好了。


以上为使用 mybatis Plus 框架时的一些开发记录,也适用于以后的项目当中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章