速通 MyBatis-Plus , 深入浅出 实战演示

目录

速通 MyBatis-Plus , 深入浅出 实战演示

1、简单介绍

MyBatis-Plus 官网

MyBatis-Plus 是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

2、项目演示(CRUD操作及其扩展延伸的操作)

2-1:简单通过 MyBatis-Plus 查询单表所有数据

2-1-1:创建项目

我这边先创建一个 springboot 项目,按个人爱好取名。

2-1-2:添加依赖

目前就先添加 mybatis-plus插件依赖、mysql数据库驱动依赖 和 lombok 依赖。

官网的依赖如图:

java 复制代码
        <!-- mybatis-plus插件依赖 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>

        <!--  mysql数据库驱动依赖  -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
2-1-3:Navicat 添加数据库并初始化数据

这里的创建基础数据的 SQL 可以直接从官网的 快速开始 那里拷贝。

sql 复制代码
DROP TABLE IF EXISTS `user`;

CREATE TABLE `user`
(
    id BIGINT NOT NULL COMMENT '主键ID',
    name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
    age INT NULL DEFAULT NULL COMMENT '年龄',
    email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
    PRIMARY KEY (id)
);

INSERT INTO `user` (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
2-1-4:简单创建一个 User 实体类
java 复制代码
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
2-1-5:创建 Mapper 接口(相当dao接口)

如图,只需简单继承 MyBatis-Plus 的 BaseMapper 接口即可,暂时无需自己写查询方法。

java 复制代码
/**
 * 继承 mybatisplus 的 BaseMapper 接口,就可以用到 mybatisplus 的功能了。
 * BaseMapper<User> 的 User 表示这个 UserMapper 接口操作的是 User 这个实体类
*/
//@Repository 也可以用这个注解代表这个接口是持久层
@Mapper
public interface UserMapper extends BaseMapper<User> {
    //不需要像以前一样写各种查询方法了,继承这个BaseMapper,已经帮我们把crud编写完成了
}
2-1-6:配置文件添加连接数据库的配置
java 复制代码
spring.application.name=mybatis-plus

# 连接数据库
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
2-1-7:IDEA 添加 MySQL
2-1-8:启动类添加 @MapperScan 注解扫描 mapper
2-1-9:简单写个测试,成功查询表中所有数据

查询成功

2-2:配置日志--查看SQL具体执行命令

java 复制代码
# 配置日志-- StdOutImpl 默认的控制台输出
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

如图,配置完就可以在控制台查看 SQL 的执行步骤了。

2-3:插入一条数据--->主键生成策略

Mybatis-Plus 这里简单说成 MP

2-3-1:MP 默认自动生成id ---> 雪花算法

snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。

其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。

如图,使用 Mybatis-Plus 实现出入一条数据,如果我们不指定 id ,那么MP会自动帮我们回填 id ,id 是通过推特的雪花算法实现的。

2-3-2:自增id ---> @TableId(type = IdType.AUTO)

如图,两个条件都满足后,就能实现id的自动递增:

条件1:ID 字段 添加注解:@TableId(type = IdType.AUTO)

条件2:MySQL 的 ID 列,需要勾选上 【自动递增】的选项。

TableId 的一些源码解释:

INPUT 的话,如果我们不手动给对象设置id,会报错

@TableId(type = IdType.INPUT)

private Long id;

注意:如果数据库的【自动递增】选项有勾选上的话,即使插入的对象没有设置id,那么插入的对象的id也是自动递增的。

如果数据库的【自动递增】选项没有勾选上,插入的对象有没有手动填写id,那么就会直接报错。

2-4:更新操作

2-4-1:简单更新操作 --->MP会通过条件自动拼接SQL

我这里修改了年龄和名字这两个字段的数据,可以看出,当该对象需要修改多个字段数据时,那么 MP 会自动帮我们 动态的拼接SQL

只修改单个字段数据的是这样的,对比一下:

2-4-2:自动填充 ---> 【自定义处理类】实现【创建时间、修改时间】的字段的数据自动填充

更新时自动更新一些固定字段(如:创建时间、修改时间 字段)

2-4-2-1:数据库增加 创建时间、修改时间 列

先给数据库表新增几个固定的字段,如 创建时间、修改时间

2-4-2-2:同步 User 实体类的字段 ---> @TableField(fill = FieldFill.INSERT)
2-4-2-3:创建一个处理器类,实现自动填充的功能

通过实现 MetaObjectHandler 接口,重写 insertFill 和 updateFill 方法,实现插入和修改数据时,时间的自动插入和更新。

java 复制代码
//作为组件交给spring容器进行管理--自动填充日期时间的处理器
@Component
@Slf4j
public class createAndUpdateHandler implements MetaObjectHandler {

    /**
     * 插入时的填充策略--根据名字去填充
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("插入数据时自动填充开始.........");
        //参数1:要修改的字段名  参数2:要插入的字段值   参数3:要给哪个数据处理
        this.setFieldValByName("createTime", new Date(), metaObject);
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
    /**
     * 更新时的填充策略
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("更新数据时自动填充开始.........");
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
}
2-4-2-4:测试插入和更新

插入一条新数据,插入时间和更新时间正确。

修改一条数据,创建时间不变,修改时间变化,代码正确。

2-5:使用 MyBatis-plus 的乐观锁插件进行演示

2-5-1:官网乐观锁插件代码

官网的乐观锁插件讲解及一些配置插件

乐观锁:简单来说就是十分乐观,它总认为每次修改都不会出现问题,无论干什么都不用上锁,只需要在修改值的时候通过 version 值判断一下,该值是否在修改的过程中被其他线程修改过,如果没有,则修改成功;如果被其他线程修改过了,则重新自旋。

2-5-1:给数据库中的 User 表增加 Version 字段

先把version版本号的默认值设置为1

2-5-2:实体类添加对应的字段
2-5-3:注册 乐观锁 组件 --> 添加配置类 (@Bean对象)

把官网的乐观锁插件代码直接拷贝过来即可。

顺便添加个依赖

java 复制代码
@MapperScan("cn.ljh.mybatisplus.mapper") //扫描功能放在这个配置类即可,不用放在启动类
@EnableTransactionManagement //开启自动管理事务的注解,默认也是开启的
@Configuration //配置类
public class MyBatisPlusConfig{

    //注册乐观锁插件---可去官方文档获取代码
    //这是一个拦截器,在执行所有操作的时候会进行拦截,然后进行自动化的处理
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

依赖:

java 复制代码
        <!-- 使用 MyBatis-plus 乐观锁插件时,需要添加的依赖 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-extension</artifactId>
            <version>3.5.0</version>
        </dependency>
2-5-4:测试类测试乐观锁
测试乐观锁--修改数据成功演示(单线程演示)

这是简单的单线程演示,主要是看 MyBatis-Plus 在执行修改操作时,会自动带上 verison 版本号作条件判断。

测试乐观锁--修改数据失败演示(多线程演示)

可以看出,线程A在执行修改的过程中,线程B 出入进来并先于线程A 完成对 id=1 的数据的修改,因为线程B修改成功,所以该数据的版本号 +1 ,然后线程A再执行修改的时候,发现版本号在修改期间已经发生变化了,所以线程A修改失败,接下来会采用 CAS 自旋锁的方式多次尝试提交。

看下 SQL 的执行日志

2-5-5:简化乐观锁插件的代码

上面的是直接拷贝官网的代码丢进来,因为后面在弄 SQL 性能分析插件的时候,有些依赖出现冲突,所以这里改下看能不能使用。

经过测试类测试,这个简化的代码写法也能实现相同的乐观锁功能(版本号判断)。

java 复制代码
    // 简化下乐观锁插件代码
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        log.info("使用到 MyBatis-Plus 乐观锁插件------------------------------------------------------");
        return new OptimisticLockerInterceptor();
    }

2-6:查询操作

2-6-1:简单的根据id查询数据
2-6-2:测试批量查询

批量查询,MP 这里是通过 IN 关键字来实现的。

java 复制代码
    //测试批量查询
    @Test
    void selectBatchIdsTest(){
        //批量查询
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L));
        //遍历循环打印
        users.stream().forEach(System.err::println);
    }
2-6-3:按条件查询之一:使用 Map 操作

注意:使用 Map 操作来查询,SQL 的查询条件是通过 AND 来拼接的。

具体源码:

2-7:分页查询 --->使用MP的分页插件

2-7-1:官网分页插件代码

先看官网的 分页插件

这个是官网提供的分页插件代码:

java 复制代码
@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {

    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加
        // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
        return interceptor;
    }
}
2-7-2:在配置类添加分页插件(@Bean对象)

直接拷贝过来,我这里修改了方法的名称。

2-7-4:测试类测试分页插件功能
2-7-5:简化分页插件的代码

上面的是直接拷贝官网的代码丢进来,因为后面在弄 SQL 性能分析插件的时候,有些依赖出现冲突,所以这里改下看能不能使用。

经过测试类测试,这个简化的代码写法也能实现相同的分页插件功能。

2-8:物理删除操作

2-8-1:根据 id 删除单条数据
2-8-1:根据 id 批量 删除数据
2-8-1:根据 map 按条件删除

注意:通过 Map 按条件删除数据,动态拼接删除条件用的是 AND 。

2-9:逻辑删除操作

物理删除:直接从数据库中删除掉。

逻辑删除:没有删除掉,只是通过修改一个变量让其失效,在查询的时候,带上该变量即可。

2-9-1:User表 添加一个 deleted 字段
2-9-2:实体类 添加一个 deleted 字段(只需添加 @TableLogic 注解即可实现逻辑删除功能)

如图:根据官网提示,给逻辑删除字段添加一个 @TableLogic 注解。

只需要添加 @TableLogic 注解 这个逻辑删除的注解,就可以实现逻辑删除功能了,

经过测试,默认数据未删除时,deleted = 0;

数据已删除时,deleted=1;

2-9-3:配置文件 添加 逻辑删除配置(现在不用添加该配置也可以,仅用于记录)

后面经过测试,即使没有配置这个,也能进行逻辑删除。MP 默认逻辑删除的字段值为 1。

2-9-4:测试逻辑删除

注意:逻辑删除其实就是一个更新deleted字段的更新操作而已。

执行删除,再也不是物理删除了。

该条记录依然存在数据库,只是 deleted 字段的值发生变化而已。

2-9-5:测试查询已经被逻辑删除的数据

如图,数据库表有该条记录,但是没查出来,因为 deleted 字段添加了 @TableLogic 逻辑删除注解后,执行删除时,MP 会自动拼接这个【AND deleted= 0】 的查询条件。

默认 deleted = 0 为【未删除】,deleted = 1为【已删除】

3、SQL性能分析

对于开发中遇到的慢SQL,我们可以使用 MP 提供的性能分析插件来检测,如果该 SQL 执行的时间超过我们设置的时间,就停止运行。

3-1:性能分析插件

作用:SQL 性能分析拦截器,用于输出每条 SQL 语句及其执行时间。

正式开发环境,这个插件就不能部署上去了,只能在开发的时候自己测试使用。

3-1-1:配置类添加性能分析的插件(@Bean对象)
3-1-1:配置文件中配置当前项目开发环境为 dev

注意:因为我这个插件和上面的分页和乐观锁插件的版本起冲突了,先把代码思路写下来,版本冲突后续再解决。

官网的性能插件分析描述

4、条件查询器 Wrapper(实现复杂查询)

官网的条件构造器描述

条件查询

4-1:查询 name、Email 不为空,age >= 20 的用户【 isNotNull、ge 】

isNotNull:不为空

ge:大于等于

java 复制代码
    //查询 name、Email 不为空,age >= 20 的用户
    @Test
    void selectListTest(){
        //封装查询条件的对象
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .isNotNull("name")   //name 不为空
                .isNotNull("email")  //email  不为空
                .ge("age",20);   //age  >= 20
        userMapper.selectList(queryWrapper).forEach(System.err::println);
    }
4-2:查询名字等于 xxx 的一条数据【 eq、 selectOne 】

selectOne:查询一条数据

注意:如果查询一个数据,可能会出现多条数据的话,需要用 List 或者 Map 接收,否则会报错

java 复制代码
    //查询名字等于 xxx 的一条数据
    @Test
    void selectOneTest(){
        //创建封装查询条件的Wrapper对象
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //如果查询一个数据,可能会出现多条数据的话,需要用 List 或者 Map 接收,否则会报错
        queryWrapper.eq("name","老白");
        User user = userMapper.selectOne(queryWrapper);
        System.err.println(user);
    }
4-3:查询名字等于 xxx 的数据,返回多条数据【 eq、 selectList 】

selectList :查询多条数据

查询名字等于 xxx 的数据,会返回多条数据, List 或者 Map 接收

java 复制代码
    //查询名字等于 xxx 的数据,会返回多条数据, List 或者 Map 接收
    @Test
    void selectOnesTest(){
        //创建封装查询条件的Wrapper对象
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name","老紫");
        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.err::println);
    }
4-4:查询年龄在 20 - 30 之间的用户 【 between 】

between 是闭区间,age = 20 和 age = 30 都会查出来

java 复制代码
    //查询年龄在 20 - 30 之间的用户
    @Test
    void te(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //是闭区间,age = 20 和 age = 30 都会查出来
        queryWrapper.between("age","20","30");
        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.err::println);
    }
4-5:查询年龄在 20 - 30 之间的用户有几个 【 between 、selectCount 】

selectCount:查询符合条件的数据条数。

java 复制代码
    //查询年龄在 20 - 30 之间的用户有几个
    @Test
    void betweenAndCountTest(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //是闭区间,age = 20 和 age = 30 都会查出来
        queryWrapper.between("age","20","30");
        Integer UserCount = userMapper.selectCount(queryWrapper);
        System.err.println("该区间用户数量:" + UserCount);
    }

模糊查询

4-6:模糊查询【 like、notLike、likeRight 】

likeLeft:就是 % 放左边,相当于 %xxx

likeRight:相当于 xxx%

java 复制代码
    // 模糊查询【 like、notLike、likeRight 】
    @Test
    void test(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        // notLike:相当于 not Like "%红%"
        // likeRight:相当于 "xxx%",right 就表示 % 放在右边,说明这里是以 xxx 为开头
        queryWrapper
                .like("name","紫")  // %紫%
                .notLike("name","白")  // %白%
                .likeRight("email","123"); // 123%
        List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
        maps.forEach(System.err::println);
    }

其他查询

4-7:子查询 【 inSql 】
java 复制代码
    // id 在子查询中查出来
    @Test
    void inSqlTest(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.inSql("id","select id from user where id < 8");

        List<Object> objs = userMapper.selectObjs(queryWrapper);
        objs.forEach(System.err::println);
    }
4-8:排序---根据 id 倒序排序
java 复制代码
    // 排序---根据 id 倒序排序
    @Test
    void orderByDescTest(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("id");

        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.err::println);
    }
相关推荐
鹿屿二向箔1 小时前
基于SSM(Spring + Spring MVC + MyBatis)框架的咖啡馆管理系统
spring·mvc·mybatis
aloha_78911 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
毕业设计制作和分享11 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis
paopaokaka_luck15 小时前
基于Spring Boot+Vue的助农销售平台(协同过滤算法、限流算法、支付宝沙盒支付、实时聊天、图形化分析)
java·spring boot·小程序·毕业设计·mybatis·1024程序员节
cooldream200915 小时前
Spring Boot中集成MyBatis操作数据库详细教程
java·数据库·spring boot·mybatis
不像程序员的程序媛16 小时前
mybatisgenerator生成mapper时报错
maven·mybatis
小布布的不19 小时前
MyBatis 返回 Map 或 List<Map>时,时间类型数据,默认为LocalDateTime,响应给前端默认含有‘T‘字符
前端·mybatis·springboot
背水21 小时前
Mybatis基于注解的关系查询
mybatis
free_girl_fang21 小时前
高效作业之Mybatis缓存
java·ide·缓存·mybatis
十二同学啊1 天前
Mybatis拦截器中获取@RequestBody表单的值修改查询SQL
数据库·sql·mybatis