• MybatisPlus基本使用(MP快速上手)


    目录

    概述

    MP快速上手(基本操作)

     SpringBoot中MyBatisPlus环境搭建

    增删改查

    分页

    条件查询(聚合,模糊,匹配范围)

    条件:范围匹配 (大于小于等于...)

    优化查询条件书写()

    条件:查询投影

    条件:模糊查询(非全文检索)

     条件:聚合函数和分组

    条件:排序操作        

    条件判断(条件为null时情况处理)

    字段映射和表名映射

    id生成策略

    ​编辑

    多数据操作


    概述

    MyBatisplus(简称MP)是基于MyBatis框架基础上开发的增强型工具。

    作用:简化开发,提高效率。 

    MP核心:为简化开发而生。

    MP由国人开发,在 Mybatis 的基础上只做增强不做改变,MP中内置了一些常用访问数据库数据的方法,例如CRUD方法等,我们不需要声明就直接可以使用。


    MP快速上手(基本操作)

     下面就使用Spring-Boot工程作为基本来介绍MP的使用。如下的介绍中,只针对数据层进行使用测试,并不涉及业务层和表现层。

     SpringBoot中MyBatisPlus环境搭建

    ,在SpringBoot中配置MP环境很简单,只需要导入MP的起步依赖,配置数据源,完善数据表和pojo类,设置数据层接口,然后调用即可。

    一、创建Boot工程,导入MP依赖

    说明:

    1.使用正统方式创建(start.spring.io),在选择起步依赖时,并没有MyBatisPlus的选项,没有关系,直接创建,创建好之后再导入依赖即可。

    2.使用阿里云(start.aliyun.com)创建boot工程,就会存在MP的起步依赖,直接选择即可。

     官方方式创建boot工程起步依赖选择

    8127d4854e064546a7e6c74244ef43ee.png

    阿里云方式创建boot工程起步依赖选择

    2e9e82f29ace4823a001dd2bf534accf.png

     使用官方方式创建后,手动导入MP起步依赖:

    1. <dependency>
    2. <groupId>com.baomidougroupId>
    3. <artifactId>mybatis-plus-boot-starterartifactId>
    4. <version>3.4.2version>
    5. dependency>

    二、配置数据源

    在此使用druid的数据源,使用druid的起步依赖后可以进行如下方式书写。方式不用一致,配置好数据源信息即可。

    1. spring:
    2. datasource:
    3. druid:
    4. driver-class-name: com.mysql.cj.jdbc.Driver
    5. url: jdbc:mysql://localhost:3306/test
    6. username: root
    7. password: root

    三、准备测试数据表和实体类

    在此使用test数据库下的account表,表字段和数据信息如下:

    8761124eb6424a7e967258b439833772.png

     书写与之对应的实体类

    说明: 在此使用lombok配置实体类,lombok为快速开发实体类的工具,只需要加几个注解就可以实现实体类的get、set、toString等方法,想要使用,需要导入依赖坐标即可。

    1. @Data
    2. @AllArgsConstructor
    3. @NoArgsConstructor
    4. public class Account {
    5. private int id;
    6. private String name;
    7. private double balance;
    8. }

    lombok坐标

    1. <dependency>
    2. <groupId>org.projectlombokgroupId>
    3. <artifactId>lombokartifactId>
    4. <version>1.18.22version>
    5. dependency>

    四、设置数据层接口

    1. @Mapper
    2. public interface AccountDAO extends BaseMapper {
    3. }

    至此,MP环境就搭建好了,因为MP内置了许多常用的方法,所有我们直接就可以测试了。 

     工程结构:

    9293c67295aa408aba05ab48cb74c985.png

     五、测试,通过下面的基本使用进行测试。


    增删改查

    做完上述的准备工作,把MP的环境搭建好以后,就可以开始使用MP了。先从最基本的CRUD开始:测试在测试类下进行(只使用数据层做测试)。

    871356b832474b9aa631b5bdf2968f54.png

     基本CURD操作

    1. //自动装配数据层接口
    2. @Autowired
    3. private AccountDAO accountDAO;
    4. //增添数据
    5. @Test
    6. void insertTest(){
    7. Account account = new Account(7, "Mh", 6000);
    8. accountDAO.insert(account);
    9. }
    10. //删除数据
    11. @Test
    12. void deleteTest(){
    13. accountDAO.deleteById(7);
    14. }
    15. //修改数据
    16. @Test
    17. void updateTest(){
    18. Account account = new Account(6, "MH", 6000);
    19. accountDAO.updateById(account);
    20. }
    21. //根据ID查询单个信息
    22. @Test
    23. void selectTest() {
    24. Account account = accountDAO.selectById(1);
    25. System.out.println(account);
    26. }
    27. //获取表中所有数据
    28. @Test
    29. void selecAlltTest() {
    30. //selectList参数为null,代表没有查询条件
    31. List accounts = accountDAO.selectList(null);
    32. accounts.forEach(System.out::println);
    33. }

    分页

    分页操作MP内部也有实现,不过并不像上面的CRUD这样简单,我们需要去做一些配置。

    MP实现分页查询步骤:

    1.需要先添加拦截器-分页拦截器
    2.创建IPage实现类,构造器初始化Page
    3.IPage调用方法,获取数据信息

    实现:

    1.创建MP拦截器类,添加分页内置拦截器。

    1. @Configuration
    2. public class MPConfig {
    3. @Bean
    4. public MybatisPlusInterceptor getInterceptor(){
    5. //创建MP拦截器
    6. MybatisPlusInterceptor MPInterceptor = new MybatisPlusInterceptor();
    7. //添加分页拦截器
    8. MPInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
    9. //将设置好的拦截器返回
    10. return MPInterceptor;
    11. }
    12. }

    2.创建并初始化IPage实现类,实现分页查询

    1. @Test
    2. void selectPageTest(){
    3. //创建IPage实现类,参数为(当前页数,每页记录数)
    4. IPage page = new Page(1,2);
    5. //参数null为条件-无条件查询
    6. accountDAO.selectPage(page,null);
    7. page.getPages(); // 获取总页数
    8. page.getCurrent(); // 获取当前页数
    9. page.getRecords(); // 获取记录(数据)
    10. page.getSize(); // 获取每页记录数
    11. page.getTotal(); // 获取记录总数
    12. //将想要得到的信息输出即可
    13. }

    条件查询(聚合,模糊,匹配范围)

    条件:范围匹配 (大于小于等于...)

    在上述的操作中,例如selectList,selectPage等,都有一个参数我们设置为null,如果不设置为null,那这个条件参数我们要怎么设置呢?如下说明:

    ad2bac740b0649e5838531982f59d8af.png

     拿selectList举例,可以看到条件参数的类型为queryWrapper,那么我们就创建一个queryWrapper对象看看。

    QueryWrapper qw = new QueryWrapper<>();

    可以使用qw对象.的方式看看有哪些方法:

    db69387d0a7247278b4787b3e7f7b33e.png

     看到列出来了许多条件,最基本的条件说明:

    大于gt

    小于 lt

    大于等于 ge

    小于等于 le

    等于 eq

    区间 between

    我们就拿lt来举例,我们就设置条件为balance小于6000的。就应该这样写:

    设置好条件后将条件对象给到selectList

    1. @Test
    2. void selecAlltTest() {
    3. QueryWrapper qw = new QueryWrapper<>();
    4. qw.lt("balance",6000);
    5. List accounts = accountDAO.selectList(qw);
    6. accounts.forEach(System.out::println);
    7. }

    查询结果: 

    4246d15fd2ef4a02b46fc300fc8d8f7d.png

    优化查询条件书写()

    优化说明:由于qw.lt("balance",6000);这样的写法,balance是我们手动通过字符串的方式输入的,可能会存在人为书写时的错误,这时候我们就可以使用LambdaQueryWrapper,因为这样的写法会对属性进行语法检查,可以避免一些错误,使用如下:

    1. @Test
    2. void selecAlltTest() {
    3. //QueryWrapper qw = new QueryWrapper<>();
    4. //qw.lt("balance",6000);
    5. LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
    6. lqw.lt(Account::getBalance,6000);
    7. List accounts = accountDAO.selectList(lqw);
    8. accounts.forEach(System.out::println);
    9. }

    多条件设置方式:

    在此设置条件为balance大于6000,小于9000。

    1. @Test
    2. void selecAlltTest() {
    3. LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
    4. //方式1
    5. lqw.lt(Account::getBalance,9000);
    6. lqw.gt(Account::getBalance,6000);
    7. //方式2:链式编程
    8. lqw.lt(Account::getBalance,9000).gt(Account::getBalance,6000);
    9. List accounts = accountDAO.selectList(lqw);
    10. accounts.forEach(System.out::println);
    11. }

    查询结果: 

     f6f50a7deec048e6b629fade58ace3d6.png

    说明:在如上的操作中,关系均为and(默认),如果想使用or关系,可以这样写:

    1. @Test
    2. void selecAlltTest() {
    3. LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
    4. //方式1
    5. lqw.lt(Account::getBalance,9000);
    6. lqw.or().gt(Account::getBalance,6000);
    7. //方式2:链式编程
    8. lqw.lt(Account::getBalance,9000).or().gt(Account::getBalance,6000);
    9. List accounts = accountDAO.selectList(lqw);
    10. accounts.forEach(System.out::println);
    11. }

    至于其他的范围条件,例如等于eq,范围between,用法基本一致。 

    条件:查询投影

    查询投影,说白了就是:设置需要查询的字段。例如:select id from tb_test

    里面的id,就是我们设置查询的字段。

    1. //条件查询测试
    2. @Test
    3. void selectAllConditionTest() {
    4. LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
    5. lqw.select(Account::getName,Account::getBalance);
    6. List accounts = accountDAO.selectList(lqw);
    7. accounts.forEach(System.out::println);
    8. }

    说明:如果使用的是QueryWrapper,在select()中直接使用字符串传入即可。 

    条件:模糊查询(非全文检索)

    使用模糊查询,可以使用like,leftLike,rightLike ,他们的区别就是,把%放到什么位置,like放到两边

    %like%,leftLike放左边%leck ,相当于是以什么结尾。rightLike相似。

    在此演示name中包含字符"J"的记录了:

    1. @Test
    2. void selectAllConditionTest() {
    3. LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
    4. lqw.like(Account::getName,"J");
    5. List accounts = accountDAO.selectList(lqw);
    6. accounts.forEach(System.out::println);
    7. }

    查询结果

    a6a327eba0984eb5910150e73b538f81.png

     条件:聚合函数和分组

    在使用聚合函数和分组时,我们就不可以使用LambdaQueryWrapper了,只能使用QueryWrapper。使用如下(测试count):

    1. //测试聚合函数和分组
    2. @Test
    3. void selectAllConditionTest1() {
    4. QueryWrapper qw = new QueryWrapper<>();
    5. qw.select("count(*)"); // 计数
    6. qw.groupBy("balance"); // 根据balance分组
    7. List> maps = accountDAO.selectMaps(qw);
    8. System.out.println(maps);
    9. }

    输出结果 

    3f997e82dc3e489e8bd10061e8cc0d92.png 结果说明,数据表数据: 

    7e4283c34be44e4fade3690123afc194.png

    条件:排序操作        

    排序操作演示:

    1. //MP查询排序
    2. @Test
    3. void selectConditionSort(){
    4. QueryWrapper qw = new QueryWrapper<>();
    5. qw.orderByAsc("balance");
    6. List accounts = accountDAO.selectList(qw);
    7. accounts.forEach(System.out::println);
    8. }

    说明:在其中orderByAsc为升序排序,要想使用降序,应该为orderByDesc ,我想这应该不用解释,SQL的知识。

    查询结果: 

    291888437e3a4da4ae9f06f4dfc6c6b6.png

    条件判断(条件为null时情况处理)

    条件判断为null时,应用场景:当一个值的范围有上限和下限时,用户如果只设置一个,例如只设置上限,就应该以这一个条件进行查询,下限没设置就默认为null,,null的话就会报错,这是不合理的,合理情况应该是:当用户没有设置该条件时,条件应当不生效。当,因此需要对此进行判断处理(处理数据为null的情况)。相当于是动态SQL的处理情况。

    需求:现在想要根据余额(balance)查询用户的信息,我们可以设置单独设置上限或下限,获取两者都设置,两者都设置的情况相当于区间。理想的情况是:当我们只设置一个条件时,例如,只设置上限,那么下限这个条件就不应该设置。这个时候,我们就要使用判断来做(判断条件是否为null)。

    1. //条件查询(条件为null的处理情况)
    2. @Test
    3. void selectConditionCaseNull(){
    4. //设置标记:标记为1条件存在 标记为0条件不存在
    5. //下限标记
    6. int downFlag = 1;
    7. //上限标记
    8. int upFlag = 0;
    9. LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
    10. //当upFlag不等于0,相当于上限条件已经设置,那么就查询记录中balance小于9000的记录。
    11. lqw.lt(0 != upFlag ,Account::getBalance,9000);
    12. //当upFlag不等于0,相当于下限条件已经设置,那么就查询记录中balance大于6000的记录。
    13. lqw.gt(0 != downFlag,Account::getBalance,6000);
    14. //由上面设置的标记,条件应该是只设置了下限,那么查询结果应该是大于6000
    15. List accounts = accountDAO.selectList(lqw);
    16. accounts.forEach(System.out::println);
    17. }

    查询结果:

    发现确实只有一个条件执行。 

    f2e5207698314679a8a54edd819e5175.png


    字段映射和表名映射

    字段映射和表名映射说的主体就是"编码属性"和"表中字段"。

    作用:解决实体类编码时的属性和表中字段匹配情况,解决表名和类名匹配的情况。以及字段限值问题。

    **解决1**

    情况:当我们的表名和实体类名不一致时,因为我们使用MP的内置方法时,传入的只有实体类的泛型,MP会根据这个传入的泛型去找到对应的操作表,我们知道传入的泛型就是实体类,如果实体类的类名和表中的表名不一致,那么就会导致找不到表,导致错误。先看一下报错信息:

    表名和实体类名 

    9d2292098aaf443487d163995f8324be.png

    43f57d10054f434d978f5b61ea9b0d88.png  

    报错信息:可以看到是Table 'test.account1' doesn't exist",同步异常,也就是无法匹配,表xx不存在。

    32a52fa4844e4615963889e24f1b5449.png

     解决方案:

    方案1:我们可以将实体类名改为Account,和数据库表保持一致。但是并不是最优解,因为我们在表的命名,一般有特殊要求,比如需要添加表名前缀tbl_等要求。则一般使用方案2。

    方案2:在实体类上添加注解:@TableName("account"),但是如果是以这样的方式,那么我们将要给每一个实体类都添加一个注解,这是繁琐的。所以,我们可以将这个东西写到全局配置中,也就是写到配置文件中。书写方式如下:

     说明:由于表名一般设置前缀,但是实体类名不会设置前缀才会导致实体类名和表名不一致问题。所以我们一般会到配置文件中设置表名前缀,解决问题。

    f0dcc22e739a42cb9e6b650ed1ad7410.png


    id生成策略

    前置条件:需要将实体类ID属性的类型改为Long。表中的字段类型改为bigint。

    id生成策略,说的就是我们insert操作时,对主键ID的设置,当我们没有设置ID的生成策略时,如果表中ID设置了自增,就会自动的生成自增ID,如果想要手动输入ID而不用自动生成,获取想要一个随机的ID,这样的设置,就是控制ID的生成策略。

    设置方法:在配置文件中设置

    可以看到支持的id生成策略:

    d8c7e6239e914ce1a2982aee6bffe623.png

     支持的ID生成策略说明:

    71e911a809154ee384907930c68c9296.png

    雪花算法说明:

    使用雪花算法生成的ID样子:" 一串很长的数字"

    36e5826112a04802a98eb7f3d3c8d74d.png

     雪花算法:根据时间戳,机器码和序列号生成一个64位的二进制转为十进制。

    62eba4456a6749c18b7bf73edf2592d7.png


    多数据操作

     多数据操作说的就是:一次性多数据删除和多数据查询。

    操作:调用对应方法,参数传入集合。

    演示:

    1. //批量删除
    2. @Test
    3. void deletes(){
    4. List ids = new ArrayList<>();
    5. ids.add(8l);
    6. ids.add(9l);
    7. accountDAO.deleteBatchIds(ids);
    8. }
    9. //批量查询
    10. @Test
    11. void selects(){
    12. List ids = new ArrayList<>();
    13. ids.add(1l);
    14. ids.add(2l);
    15. accountDAO.selectBatchIds(ids);
    16. }

    测试结果: 

    341251a64250434e86005e1b024b38c0.png

    3b98e6a04e164741983dcf44a9918278.png

  • 相关阅读:
    适用于企业级的勒索软件风险防范规范
    聚乙二醇表面修饰氧化锌量子点/FA-PEG-CdTe/CdS量子点荧光探针特异性标记Hep-2的制备
    Druid数据库连接池
    黑猫带你学Makefile第9篇:menuconfig/Kconfig/deconfig/.config及Makefile之间的关系
    【SpringCloud微服务全家桶学习笔记-GateWay网关(微服务入口)】
    探索未来:大模型技术的最前沿
    Effective-java-读书笔记之异常
    C语言测试题:用冒泡法对输入的10个字符由小到大排序 ,要求数组做为函数参数。
    我开源了团队内部基于SpringBoot Web快速开发的API脚手架stater
    PostgreSQL数据库统计信息——examine_attribute单列预分析
  • 原文地址:https://blog.csdn.net/m0_60155232/article/details/127660497