MyBatis Plus

MyBatisPlus简介

入门案例

开发方式:
  基于MyBatis使用MyBatisPlus
  基于Spring使用MyBatisPlus
  基于SpringBoot使用MyBatisPlus

SpringBoot整合MyBatis开发过程(复习):
  1.创建SpringBoot工程
  2.勾选配置使用的技术
  3.设置dataSource相关属性(JDBC参数)
  4.定义数据层接口映射配置

SpringBoot整合MyBatisPlus入门程序

1.创建新模块,选择Spring初始化,并配置模块相关基础信息

2.选择当前模块需要使用的技术集(仅保留JDBC)

3.在pom.xml中手动添加MyBatisPlus起步依赖

 1 <dependency>
 2     <groupId>com.baomidou</groupId>
 3     <artifactId>mybatis-plus-boot-starter</artifactId>
 4     <version>3.4.1</version>
 5 </dependency>
 6 <dependency>
 7     <groupId>com.alibaba</groupId>
 8     <artifactId>druid</artifactId>
 9     <version>1.1.16</version>
10 </dependency>

注:
  由于mp并未被收录到idea的系统内置配置,无法直接选择加入
  如果使用Druid数据源,需要导入对应坐标
4.制作实体类与表结构(类名与表名对应,属性名与字段名对应)

1 public class User {
2     private Long id;
3     private String name;
4     private String password;
5     private Integer age;
6     private String tel;
7     ... //添加getter、setter、toString()等方法
8 }

5.设置Jdbc参数(application.yml

1 spring:
2   datasource:
3     type: com.alibaba.druid.pool.DruidDataSource
4     driver-class-name: com.mysql.cj.jdbc.Driver
5     url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC
6     username: root
7     password: root

6.定义数据接口,继承BaseMapper

1 @Mapper
2 public interface UserDao extends BaseMapper<User> {
3 }

7.测试类中注入dao接口,测试功能

 1 @SpringBootTest
 2 public class Mybatisplus01QuickstartApplicationTests {
 3 
 4     @Autowired
 5     private UserDao userDao;
 6 
 7     @Test
 8     void testGetAll() {
 9         List<User> userList = userDao.selectList(null);
10         System.out.println(userList);
11     }
12 }

MyBatisPlus概述

MyBatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发提高效率
官网:https://mybatis.plus/   https://mp.baomidou.com/

MyBatisPlus特性

无侵入:只做增强不做改变,不会对现有工程产生影响
强大的 CRUD 操作:内置通用 Mapper,少量配置即可实现单表CRUD 操作
支持 Lambda:编写查询条件无需担心字段写错
支持主键自动生成
内置分页插件
……

标准数据层开发

MyBatisPlus的CRUD操作

 1 @SpringBootTest
 2 class Mybatisplus01QuickstartApplicationTests {
 3     @Autowired
 4     private UserDao userDao;
 5 
 6     @Test
 7     void testSave() {
 8         User user = new User();
 9         user.setName("程序员");
10         user.setPassword("it");
11         user.setAge(12);
12         user.setTel("4006184000");
13         userDao.insert(user);
14     }
15 
16     @Test
17     void testDelete() {
18         userDao.deleteById(1401856123725713409L);
19     }
20 
21     @Test
22     void testUpdate() {
23         User user = new User();
24         user.setId(1L);
25         user.setName("Tom888");
26         user.setPassword("tom888");
27         userDao.updateById(user);
28     }
29 
30     @Test
31     void testGetById() {
32         User user = userDao.selectById(2L);
33         System.out.println(user);
34     }
35 
36     @Test
37     void testGetAll() {
38         List<User> userList = userDao.selectList(null);
39         System.out.println(userList);
40     }
41 }

根据主键查询多条记录

1 //查询指定多条数据
2 List<Long> list = new ArrayList<>();
3 list.add(1L);
4 list.add(3L);
5 list.add(4L);
6 userDao.selectBatchIds(list);

MyBatisPlus分页查询

MyBatisPlus分页使用

1.在config文件夹中创建MybatisPlusConfig配置类,设置分页拦截器作为Spring管理的bean

 1 @Configuration
 2 public class MybatisPlusConfig {
 3     @Bean
 4     public MybatisPlusInterceptor mybatisPlusInterceptor(){
 5         //1 创建MybatisPlusInterceptor拦截器对象
 6         MybatisPlusInterceptor mpInterceptor=new MybatisPlusInterceptor();
 7         //2 添加分页拦截器
 8         mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
 9         return mpInterceptor;
10     }
11 }

2.执行分页查询

 1 @Test
 2 void testSelectPage(){
 3     //1 创建IPage分页对象,设置分页参数
 4     IPage<User> page=new Page<>(1,3);
 5     //2 执行分页查询
 6     userDao.selectPage(page,null);
 7     //3 获取分页结果
 8     System.out.println("当前页码值:"+page.getCurrent());
 9     System.out.println("每页显示数:"+page.getSize());
10     System.out.println("总页数:"+page.getPages());
11     System.out.println("总条数:"+page.getTotal());
12     System.out.println("当前页数据:"+page.getRecords());
13 }

开启MyBatisPlus日志(application.yml)(用于查看开发过程日志)

1 # 开启mp的日志(输出到控制台)
2 mybatis-plus:
3   configuration:
4     log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

解决日志打印过多问题

取消初始化spring日志打印

做法:在resources下新建一个logback.xml文件,名称固定,内容如下(configuration里不写内容):

1 <?xml version="1.0" encoding="UTF-8"?>
2 <configuration>
3 
4 </configuration>

取消SpringBoot启动banner图标

spring:
  main:
    banner-mode: off # 关闭SpringBoot启动图标(banner)

取消MybatisPlus启动banner图标

# mybatis-plus日志控制台输出
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    banner: off # 关闭mybatisplus启动图标

Lombok插件介绍

Lombok,一个Java类库,提供了一组注解,简化POJO实体类开发。

1 <dependency>
2     <groupId>org.projectlombok</groupId>
3     <artifactId>lombok</artifactId>
4     <version>1.18.12</version>
5     <scope>provided</scope>  <!--不参与打包-->
6 </dependency>

常用注解:@Data
  为当前实体类在编译期设置对应的get/set方法,无参构造方法,toString方法,hashCode方法,equals方法等。只有加上@AllArgsConstructor:生成全参构造; @NoArgsConstructor:生成空参构造。

 1 /*
 2     1 生成getter和setter方法:@Getter、@Setter
 3       生成toString方法:@ToString
 4       生成equals和hashcode方法:@EqualsAndHashCode
 5 
 6     2 统一成以上所有:@Data
 7 
 8     3 生成空参构造: @NoArgsConstructor
 9       生成全参构造: @AllArgsConstructor
10 
11     4 lombok还给我们提供了builder的方式创建对象,好处就是可以链式编程。 @Builder【扩展】
12  */
13 @Data
14 public class User {
15     private Long id;
16     private String name;
17     private String password;
18     private Integer age;
19     private String tel;
20 }

DQL编程控制

条件查询方式

MyBatisPlus将书写复杂的SQL查询条件进行了封装,使用编程的形式完成查询条件的组合。

条件查询

格式一:常规格式

1 QueryWrapper<User> qw = new QueryWrapper<User>();
2 //查询年龄大于等于18岁,小于65岁的用户
3 qw.lt("age",65);
4 qw.gt("age",18);
5 List<User> userList = userDao.selectList(qw);
6 System.out.println(userList);

格式二:链式编程格式

1 QueryWrapper<User> qw = new QueryWrapper<User>();
2 //查询年龄大于等于18岁,小于65岁的用户
3 qw.lt("age",65).gt("age",18);
4 List<User> userList = userDao.selectList(qw);
5 System.out.println(userList);

格式三:lambda格式

1 QueryWrapper<User> qw = new QueryWrapper<User>();
2 //查询年龄大于等于18岁,小于65岁的用户
3 qw.lambda().lt(User::getAge,65).gt(User::getAge,18);
4 List<User> userList = userDao.selectList(qw);
5 System.out.println(userList);

格式四:lambda格式(推荐)

1 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
2 //查询年龄大于等于18岁,小于65岁的用户
3 lqw.lt(User::getAge,65).gt(User::getAge,18);
4 List<User> userList = userDao.selectList(lqw);
5 System.out.println(userList);

组合条件

并且关系(and)

1 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
2 //并且关系:10到30岁之间
3 lqw.lt(User::getAge, 30).gt(User::getAge, 10);
4 List<User> userList = userDao.selectList(lqw);
5 System.out.println(userList);

或者关系(or)

1 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
2 //或者关系:小于10岁或者大于30岁
3 lqw.lt(User::getAge, 10).or().gt(User::getAge, 30);
4 List<User> userList = userDao.selectList(lqw);
5 System.out.println(userList);

NULL值处理

if语句控制条件追加

 1 Integer minAge=10;  //将来有用户传递进来,此处简化成直接定义变量了
 2 Integer maxAge=null;  //将来有用户传递进来,此处简化成直接定义变量了
 3 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
 4 if(minAge!=null){
 5     lqw.gt(User::getAge, minAge);
 6 }
 7 if(maxAge!=null){
 8     lqw.lt(User::getAge, maxAge);
 9 }
10 List<User> userList = userDao.selectList(lqw);
11 userList.forEach(System.out::println);

条件参数控制

1 Integer minAge=10;  //将来有用户传递进来,此处简化成直接定义变量了
2 Integer maxAge=null;  //将来有用户传递进来,此处简化成直接定义变量了
3 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
4 //参数1:如果表达式为true,那么查询才使用该条件
5 lqw.gt(minAge!=null,User::getAge, minAge);
6 lqw.lt(maxAge!=null,User::getAge, maxAge);
7 List<User> userList = userDao.selectList(lqw);
8 userList.forEach(System.out::println);

条件参数控制(链式编程)

1 Integer minAge=10;  //将来有用户传递进来,此处简化成直接定义变量了
2 Integer maxAge=null;  //将来有用户传递进来,此处简化成直接定义变量了
3 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
4 //参数1:如果表达式为true,那么查询才使用该条件
5 lqw.gt(minAge!=null,User::getAge, minAge)
6    .lt(maxAge!=null,User::getAge, maxAge);
7 List<User> userList = userDao.selectList(lqw);
8 userList.forEach(System.out::println);

查询投影-设置【查询字段、分组、分页】

查询结果包含模型类中部分属性

1 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
2 lqw.select(User::getId,User::getName,User::getAge);
3 List<User> userList = userDao.selectList(lqw);
4 System.out.println(userList);

1 QueryWrapper<User> lqw = new QueryWrapper<User>();
2 lqw.select("id", "name", "age", "tel");
3 List<User> userList = userDao.selectList(lqw);
4 System.out.println(userList);

查询结果包含模型类中未定义的属性

1 QueryWrapper<User> lqw = new QueryWrapper<User>();
2 lqw.select("count(*) as count, tel");
3 lqw.groupBy("tel");
4 List<Map<String, Object>> userList = userDao.selectMaps(lqw);
5 System.out.println(userList);

查询条件设定

范围匹配(> 、 = 、between)
模糊匹配(like)
空判定(null)
包含性匹配(in)
分组(group)
排序(order)
……

查询条件

用户登录(eq匹配)

1 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
2 //等同于=
3 lqw.eq(User::getName, "Jerry").eq(User::getPassword, "jerry");
4 User loginUser = userDao.selectOne(lqw);
5 System.out.println(loginUser);

购物设定价格区间、户籍设定年龄区间(le ge匹配 或 between匹配)

1 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
2 //范围查询 lt le(等同于lt + eq) gt ge(等同于gt + eq) eq between
3 lqw.between(User::getAge, 10, 30);
4 List<User> userList = userDao.selectList(lqw);
5 System.out.println(userList);

查信息,搜索新闻(非全文检索版:like匹配)

1 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
2 //模糊匹配 like  likeLeft(等同于like '%J') likeRight(等同于 like 'J%')
3 lqw.likeLeft(User::getName, "J");
4 List<User> userList = userDao.selectList(lqw);
5 System.out.println(userList);

统计报表(分组查询聚合函数)

1 QueryWrapper<User> qw = new QueryWrapper<User>();
2 qw.select("gender","count(*) as nums");
3 qw.groupBy("gender");
4 List<Map<String, Object>> maps = userDao.selectMaps(qw);
5 System.out.println(maps);

查询API

更多查询条件设置参看  https://mybatis.plus/guide/wrapper.html#abstractwrapper

字段映射与表名映射

1.表字段与编码属性设计不同步

2.编码中添加了数据库中未定义的属性

 3.采用默认查询开放了更多的字段查看权限

 4.表名与编码开发设计不同步

@TableField
  类型:属性注解
  位置:模型类属性定义上方
  作用:设置当前属性对应的数据库表中的字段关系
  相关属性:
    value:设置数据库表字段名称
    exist:设置属性在数据库表字段中是否存在,默认为true。此属性无法与value合并使用
    select:设置属性是否参与查询,此属性与select()映射配置不冲突

@TableName
  类型:类注解
  位置:模型类定义上方
  作用:设置当前类对应与数据库表关系
  相关属性:
    value:设置数据库表名称

 1 @Data
 2 @TableName("tbl_user")
 3 public class User {
 4     /*
 5         id为Long类型,因为数据库中id为bigint类型,
 6         并且mybatis有自己的一套id生成方案,生成出来的id必须是Long类型
 7      */
 8     private Long id;
 9     private String name;
10     @TableField(value = "pwd",select = false)
11     private String password;
12     private Integer age;
13     private String tel;
14     @TableField(exist = false) //表示online字段不参与CRUD操作
15     private Boolean online;
16 }

DML编程控制

id生成策略控制(Insert)

id生成策略控制(@TableId注解)

@TableId
  类型:属性注解
  位置:模型类中用于表示主键的属性定义上方
  作用:设置当前类中主键属性的生成策略
  相关属性:
    value:设置数据库主键名称
    type:设置主键属性的生成策略,值参照IdType枚举值

1 public class User {
2     @TableId(type = IdType.AUTO)
3     private Long id;
4 }

  AUTO(0):使用数据库id自增策略控制id生成
  NONE(1):不设置id生成策略
  INPUT(2):用户手工输入id
  ASSIGN_ID(3):雪花算法生成id(可兼容数值型与字符串型)
  ASSIGN_UUID(4):以UUID生成算法作为id生成策略

默认ASSIGN_ID,雪花算法:

全局策略配置

id生成策略全局配置:

表名前缀全局配置:

全局配置:

1 mybatis-plus:
2   global-config:
3     db-config:
4       id-type: assign_id  #配置所有id生成策略为:ASSIMG_ID。
5       table-prefix: tbl_   #表示实体类上的表名可以不用写tbl_,直接写实体类名(例:@TableName("user"))

多记录删除(批量Delete)

按照主键删除多条记录:

1 List<Long> list = new ArrayList<>();
2 list.add(1402551342481838081L);
3 list.add(1402553134049501186L);
4 list.add(1402553619611430913L);
5 userDao.deleteBatchIds(list);

逻辑删除(Delete/Update)

删除操作业务问题:业务数据从数据库中丢弃。
逻辑删除:为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留在数据库中。

逻辑删除案例

1.数据库表中添加逻辑删除标记字段

2.实体类中添加对应字段,并设定当前字段为逻辑删除标记字段

1 @Data
2 public class User {
3     private Long id;   
4     //逻辑删除字段,标记当前记录是否被删除(value表示默认逻辑未删除值,delval表示默认逻辑删除值)
5     @TableLogic(value='0',delval='1')
6     private Integer deleted;   
7 }

3.可批量配置逻辑删除字面值,实体类中@TableLogic不写

 1 mybatis-plus:
 2   global-config:
 3     db-config:
 4       table-prefix: tbl_
 5       # 逻辑删除字段名
 6       logic-delete-field: deleted
 7       # 逻辑删除字面值:未删除为0
 8       logic-not-delete-value: 0
 9       # 逻辑删除字面值:删除为1
10       logic-delete-value: 1

逻辑删除本质:逻辑删除的本质其实是修改操作。如果加了逻辑删除字段,查询数据时也会自动带上逻辑删除字段。

乐观锁(Update)

乐观锁主张的思想:业务并发现象带来的问题(例:秒杀) 

乐观锁案例

1.数据库表中添加锁标记字段

 2.实体类中添加对应字段,并设定当前字段为逻辑删除标记字段

1 @Data
2 public class User {
3     private Long id;    
4     @Version
5     private Integer version;
6 }

3.配置乐观锁拦截器实现锁机制对应的动态SQL语句拼装

 1 @Configuration
 2 public class MpConfig {
 3     @Bean
 4     public MybatisPlusInterceptor mpInterceptor() {
 5         //1.定义Mp拦截器
 6         MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
 7         //2.添加乐观锁拦截器
 8         mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());        
 9         return mpInterceptor;
10     }
11 }

4.使用乐观锁机制在修改前必须先获取到对应数据的verion方可正常进行
  方式一:

1 @Test
2 public void testUpdate() {
3     User user = new User();
4     user.setId(3L);
5     user.setName("Jock666");
6     user.setVersion(1);    //需设置此条数据version字段的值
7     userDao.updateById(user);
8 } 

  方式二:

1 @Test
2 public void testUpdate() {
3     //1.先通过要修改的数据id将当前数据查询出来,间接获取到version的值
4     User user = userDao.selectById(3L);
5     //2.将要修改的属性逐一设置进去
6     user.setName("Jock888");
7     userDao.updateById(user);
8 }

原理

 1 @Test
 2 public void testUpdate() {   
 3     //1.先通过要修改的数据id将当前数据查询出来
 4     User user = userDao.selectById(3L);     //当前执行条件version=3
 5     User user2 = userDao.selectById(3L);    //当前执行条件version=3
 6     user2.setName("Jock aaa");
 7     userDao.updateById(user2);              //执行此句后version变为4
 8     user.setName("Jock bbb");
 9     userDao.updateById(user);               //执行条件verion=3 条件已不成立,无法执行该语句
10 }

快速开发-代码生成器

模板:MyBatisPlus提供
数据库相关配置:读取数据库获取信息
开发者自定义配置:手工配置

工程搭建和基本代码编写

第一步:创建SpringBoot工程,在pom.xml中添加代码生成器相关依赖,其他依赖自行添加

 1 <!--代码生成器-->
 2 <dependency>
 3     <groupId>com.baomidou</groupId>
 4     <artifactId>mybatis-plus-generator</artifactId>
 5     <version>3.4.1</version>
 6 </dependency>
 7 
 8 <!--velocity模板引擎-->
 9 <dependency>
10     <groupId>org.apache.velocity</groupId>
11     <artifactId>velocity-engine-core</artifactId>
12     <version>2.3</version>
13 </dependency>

第二步:编写代码生成器类

 1 public class Generator {
 2     public static void main(String[] args) {
 3         //1. 创建代码生成器对象,执行生成代码操作
 4         AutoGenerator autoGenerator = new AutoGenerator();
 5 
 6         //2. 数据源相关配置:读取数据库中的信息,根据数据库表结构生成代码
 7         DataSourceConfig dataSource = new DataSourceConfig();
 8         dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
 9         dataSource.setUrl("jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC");
10         dataSource.setUsername("root");
11         dataSource.setPassword("root");
12         autoGenerator.setDataSource(dataSource);
13 
14          //3. 执行生成操作
15         autoGenerator.execute();
16     }
17 }

开发者自定义配置

设置全局配置

1 //设置全局配置
2 GlobalConfig globalConfig = new GlobalConfig();
3 globalConfig.setOutputDir(System.getProperty("user.dir")+"/mybatisplus_04_generator/src/main/java");    //设置代码生成位置
4 globalConfig.setOpen(false);    //设置生成完毕后是否打开生成代码所在的目录
5 globalConfig.setAuthor("程序员");    //设置作者
6 globalConfig.setFileOverride(true);     //设置是否覆盖原始生成的文件
7 globalConfig.setMapperName("%sDao");    //设置数据层接口名,%s为占位符,指代模块名称
8 globalConfig.setIdType(IdType.ASSIGN_ID);   //设置Id生成策略
9 autoGenerator.setGlobalConfig(globalConfig);

设置包名相关配置

1 //设置包名相关配置
2 PackageConfig packageInfo = new PackageConfig();
3 packageInfo.setParent("com.aaa");   //设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径
4 packageInfo.setEntity("domain");    //设置实体类包名
5 packageInfo.setMapper("dao");   //设置数据层包名
6 autoGenerator.setPackageInfo(packageInfo);

策略设置

1 //策略设置
2 StrategyConfig strategyConfig = new StrategyConfig();
3 strategyConfig.setInclude("tbl_user");  //设置当前参与生成的表名,参数为可变参数
4 strategyConfig.setTablePrefix("tbl_");  //设置数据库表的前缀名称,模块名 = 数据库表名 - 前缀名  例如: User = tbl_user - tbl_
5 strategyConfig.setRestControllerStyle(true);    //设置是否启用Rest风格
6 strategyConfig.setVersionFieldName("version");  //设置乐观锁字段名
7 strategyConfig.setLogicDeleteFieldName("deleted");  //设置逻辑删除字段名
8 strategyConfig.setEntityLombokModel(true);  //设置是否启用lombok
9 autoGenerator.setStrategy(strategyConfig);

 

posted @ 2023-07-31 23:52  溯鸣  阅读(41)  评论(0编辑  收藏  举报