Mybatis-plus工具学习笔记---[常用注解,条件构造器,插件使用]

Posted 小智RE0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis-plus工具学习笔记---[常用注解,条件构造器,插件使用]相关的知识,希望对你有一定的参考价值。

文章目录

近期也是计划学习mybatis-plus,扩展知识;
推荐官方文档食用学习–>https://baomidou.com/
Mybatis-plus官方文档

本次学习根据B站尚硅谷教学视频:【尚硅谷】2022版MyBatisPlus教程(一套玩转mybatis-plus)


1.常用注解


1.1 @TableName


在之前学习的时候,注意到并没有指定操作哪个数据表,但是操作时它就会找到用户user数据表;这是根据实体类User来判定找到的;

那么此时将数据库中的用户表名修改后,注意观察效果; 将user 表名改为 t_user

找到之前编写的测试类MybatisPlusTest
运行测试方法;


此时发现程序报错数据表user不存在;因为默认识别的是查询数据表user,但是将数据表user改名为t_user了,也就无法匹配.

那么如何自动识别到要查询的数据表t_user呢?

两种方式:

  • 首先,可以选择在实体类User处使用注解@TableName来标注数据表的名称

    再运行测试方法试试,可成功操作对应的数据表t_user

全局配置

  • 当然,也可以选择第二种做法,在配置文件application.yml中进行配置数据表的识别;

先将刚才在实体类User写的注解@TableName("t_user")注释掉;

application.yml中配置mybatis的全局配置;对于项目使用的数据表公共前缀进行标注;

# 设置数据源类型,数据库信息;
spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    url: jdbc:mysql://127.0.0.1:3306/mybatis_plus_study_xiaozhi?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
#加入日志功能;
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  #可配置mybatis的全局配置
  global-config:
    db-config:
      table-prefix: t_

同样测试一下,也可以正常使用


1.2 @TableId


通过前面的学习,了解到mybatis-plus是默认将数据表中的id作为主键的,要是将数据表的字段id改为uid呢?是否还能正确识别到主键?

将数据表中的id修改为uid

当然,实体类User的属性id也修改为uid

MybatisPlusTest中执行测试的添加功能;

//测试新增功能;
@Test
public void startAdd() 
    User user = new User();
    user.setName("小智");
    user.setAge(22);
    user.setEmail("xiaozhi@ceshi.com");
    //新增数据;
    //INSERT INTO user ( Uid, name, age, email ) VALUES ( ?, ?, ?, ? )
    int insert = userMapper.insert(user);
    //是否添加成功;
    System.out.println("新增了" + insert + "条数据----------");
    //立即获取到添加数据的主键Id;
    System.out.println("立即获取新增的用户主键:" + user.getUid());

运行之,显而易见出现了sql错误.提示uid这个字段没有设定的默认值,即无法识别它的主键身份.

那么解决处理,可使用注解@TableId来进行标注.
打开实体类User;在属性uid上使用注解;即可将属性uid对应的字段uid标识为主键;

@Data
@NoArgsConstructor
@AllArgsConstructor
//标注数据表名;
//@TableName("t_user")
public class User 
    @TableId
    private Long uid;

    private String name;

    private Integer age;

    private String email;

测试执行刚才的添加方法,数据成功存入;


键入注解TableId,可看到value和type方法;这两个方法可操作的.

模拟场景,此时要是将用户User的属性uid改为id. 而数据表的字段仍然是uid,那么属性该如何识别到对应的字段uid呢?

可使用value属性进行标注即可;


再看看type的功能; 可操作属性的策略;
先将数据表中的uid字段设置为自增;

首先测试一下添加数据方法;

运行之,发现uid还是默认的雪花算法生成的,并不是自增的;

那么实际上就需要用注解@TableId的属性type进行标注自增属性;
可以看注解@TableId源码中的type()方法返回值类型IdType的源码,这是个枚举类,ok很容易找到这样一个方法来标注自增.

在实体类User设置即可;

@Data
@NoArgsConstructor
@AllArgsConstructor
//标注数据表名;
//@TableName("t_user")
public class User 
    //将属性对应的字段标注为主键;
    //value属性可标注对应的字段;

    @TableId(value = "uid",type = IdType.AUTO )
    private Long id;

    private String name;

    private Integer age;

    private String email;

测试执行添加数据的方法;OK,确实有自增效果了;



常见的主键设定策略:

  • 默认的:IdType.ASSIGN_ID 基于雪花算法的策略生成数据id,与数据库id是否设置自增无关
  • IdType.AUTO 使用数据库的自增策略,该类型请确保数据库设置了id自增,否则无效.

全局配置

当然,不使用注解也是可以的,在application.yml中进行全局配置即可.使用参数id-type配置主键生成策略即可.

# 设置数据源类型,数据库信息;
spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    url: jdbc:mysql://127.0.0.1:3306/mybatis_plus_study_xiaozhi?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
#加入日志功能;
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  #可配置mybatis的全局配置
  global-config:
    db-config:
      #设置实体类表的统一前缀;
      table-prefix: t_
      #可设置统一的主键生成策略;
      id-type: auto

测试新增数据,可发现执行了自增策略.


1.3 雪花算法介绍


为应对数据规模的增长,需要分析访问压力和数据量
数据库的三种扩展方式:业务分库、主从复制,数据库分表。

关于数据库分表:

垂直分表:

水平分表


1.4 @TableField


首先模拟场景,数据表字段用下划线分隔,在实体类中属性用驼峰命名.

将user中的name字段改为user_name.

在实体类User中也进行修改.


执行测试方法;


执行sql时,名称字段还是user_name,那么也就是说在mybatis-plus中有默认的下划线匹配对应驼峰.


那要是不在实体类中使用驼峰命名法呢?

执行测试方法,

在执行sql时,无法识别到对应的字段


那么,即要不用驼峰命名,还要匹配对应字段,使用注解@TableField即可.

执行测试方法;已正确识别到字段user_name.


1.5 @TableLogic


关于逻辑删除,也就是在代码逻辑上数据已经被删除,但是数据库中实际只是改变了数据的状态,数据并没有消除.\\

在数据表user中创建一个字段is_deleted,表示该数据行是否删除的转态,默认为0表示未删除,删除时修改该字段即可.


在实体类User中添加该属性.可用注解@TableLogic表明逻辑删除.

现在测试执行删除方法;一次性删除3个.

但是注意到它执行的sql语句并不是delete,而是update更新数据,将字段is_deleted由0变为了1.


当前的user数据表包含了22条数据,刚才逻辑删除3条.实际总数据应该是19条.

现在执行查询语句查看总数据量;

执行后,注意到总数据量为19条. 也就是说,逻辑删除已被认可.
执行的sql也用where来筛选is_deleted为0的数据.


2. 条件构造器


![在这里插入图片描述](https://img-blog.csdnimg.cn/4f222f0bcb444022a1a0cd3a950269b6.png)

关于条件构造器的说明

Wrapper:条件构造器的抽象类
AbstractWrapper 封装查询条件,可生成sql语句中的where条件.
QueryWrapper封装查询条件
UpdateWrapper封装更新条件
AbstractLambdaWrapper,LambdaQueryWrapper,LambdaUpdateWrapper 可使用Lambda语法


2.1 组装查询条件案例


先创建测试类MybatisPlusWrapperTest ;

import com.xiaozhi.mybatisplus.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
 * @BelongsProject: mybatis-plus
 * @BelongsPackage: com.xiaozhi.mybatisplus
 * @Author: 信计1801 李智青
 * @Date: 2022/7/1 20:27
 * @Description: 条件构造器测试
 */
@SpringBootTest
public class MybatisPlusWrapperTest 
    //自动装配;
    @Autowired
    private UserMapper userMapper;


运行测试方法1,查询数据表中,name包含xaiozhi,年龄位于20-50之间,邮箱不为空的用户.

@Test
public void testOne() 
    //查询数据表中,name包含xaiozhi,年龄位于20-50之间,邮箱不为空的用户.
    QueryWrapper<User> queryWrapper = new QueryWrapper();
    queryWrapper.like("user_name", "xiaozhi")
            .between("age", 20, 50)
            .isNotNull("email");
    //查询集合;
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);

执行结果;

SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)


2.2 组装排序案例


运行测试方法2;查询用户信息,按年龄进行降序排序.年龄相同,则按照uid排序.

@Test
public void testTwo() 
    //查询用户信息,按年龄进行降序排序.年龄相同,则按照uid排序.
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.orderByDesc("age")
            .orderByAsc("uid");
    //查询集合;
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);

运行之;

SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,uid ASC


2.3 组装删除条件案例


运行测试方法3:删除user_name为空的数据

@Test
public void testThree() 
    //删除user_name不为空的数据
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.isNotNull("user_name");
    int delete = userMapper.delete(queryWrapper);
    System.out.println("删除了" + delete + "条数据");

运行之,实际是逻辑删除.

UPDATE t_user SET is_deleted=1 WHERE is_deleted=0 AND (user_name IS NOT NULL)


2.4 修改功能案例


测试方法4:修改数据:年龄大于20,用户名包含xiaozhi,或者邮箱为空的用户.

@Test
public void testFour() 
    //修改数据:年龄大于20,用户名包含xiaozhi,或者邮箱为空的用户.
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.gt("age", 20)
            .like("user_name", "xiaozhi")
            .or()
            .isNull("email");
    User user = new User();
    user.setAge(20);
    int update = userMapper.update(user, queryWrapper);
    System.out.println("修改了" + update + "条数据");

运行之.

UPDATE t_user SET age=? WHERE is_deleted=0 AND (age > ? AND user_name LIKE ? OR email IS NULL)


2.5 条件的优先级设置


测试方法5:修改数据: 用户名包含xiaozhi,并且(年龄大于20岁或者邮箱为空的) 用户.

注意需要设置条件的优先级,不然写出来就和测试方法4差不多了.

@Test
public void testFive() 
    //修改数据: 用户名包含xiaozhi,并且(年龄大于20岁或者邮箱为空的) 用户.
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.like("user_name", "xiaozhi")
            .and(i -> i.gt("age", 20).or().isNull("email"));
    User user = new User();
    user.setAge(20);
    int update = userMapper.update(user, queryWrapper);
    System.out.println("修改了" + update + "条数据");

运行之,实际执行sql为:

UPDATE t_user SET age=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))


2.6 组装select精确查询案例


测试方法6:查询用户的名称,年龄,邮箱;;

@Test
public void testSix() 
    //查询用户的名称,年龄,邮箱;;
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.select("user_name", "age", "email");
    //查询集合;
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);

运行之,实际执行SQL为:

SELECT user_name,age,email FROM t_user WHERE is_deleted=0


2.7 组装子查询案例


测试方法7:查询uid小于100的用户.

@Test
public void testSeven() 
    //查询uid小于100的用户.
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.inSql("uid", "select uid from t_user where uid < 100");
    //查询集合;
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);

运行之,实际执行sql为:

SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (uid IN (select uid from t_user where uid < 100))


2.8 UpdateWrapper的修改功能案例


测试方法8: 修改数据: 用户名包含xiaozhi,并且(年龄大于20岁或者邮箱为空的) 用户.

@Test
public void testEight() 
    //修改数据: 用户名包含xiaozhi,并且(年龄大于20岁或者邮箱为空的) 用户.
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    updateWrapper.like("user_name", "xiaozhi")
            .and(i -> i.gt("age", "20").or().isNull("email"));
    updateWrapper.set("user_name", "小智RE0").set("age", 22);
    int update = userMapper.update(null, updateWrapper);
    System.out.println("修改了" + update + "条数据");

运行之,实际运行SQL为:

UPDATE t_user SET user_name=?,age=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))


2.9 模拟开发组装条件案例


编写一个模拟数据输入的案例

@Test
public void testNine() 
    //模拟前端输入数据;
    String userName = "xiaozhi";
    Integer ageStart = 22;
    Integer ageEnd = 230;
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //isNotBlank 判断字符串序列不是 null ,不是空白
    if (StringUtils.isNotBlank(userName)) 
        queryWrapper.like("user_name", userName);
    
    if (ageStart != null) 
        queryWrapper.ge("age", ageStart);

    
    if (ageEnd != null) 
        queryWrapper.le("age", ageEnd);

    
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);

运行之,实际运行SQL为:

SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age >= ? AND age <= ?)


2.10 使用Condition组装条件案例


测试方法10:

@Test
public void testTen() 
    //模拟前端输入数据;
    String userName = "xiaozhi";
    Integer ageStart = 20;
    Integer ageEnd = 230;
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //isNotBlank 判断字符串序列不是 null ,不是空白;
    //这里用了布尔类型的参数condition作为判断先行条件;
    queryWrapper.like(StringUtils.isNotBlank("user_name"), "user_name", userName)
            .ge(ageStart != null, "age", ageStart)
            .le(ageEnd != null, "age", ageEnd);
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);

运行之,实际执行sql为:

SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age >= ? AND age <= ?)


2.11 LambdaQueryWrapper案例


测试方法11:

@Test
public void testEleven() 
    //模拟前端输入数据;
    String userName = "xiaozhi";
    Integer ageStart = 20;
    Integer ageEnd = 230;
    LambdaQueryWrapper<User> queryWrapper = 以上是关于Mybatis-plus工具学习笔记---[常用注解,条件构造器,插件使用]的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis-plus工具学习笔记---[基本概述,入门案例搭建,通用service接口使用]

mybatis-plus学习笔记

Mybatis-plus工具学习笔记---[基本概述,入门案例搭建,通用service接口使用]

#yyds干货盘点#MyBatis-plus学习笔记

Mybatis-Plus入门学习笔记

Mybatis-Plus学习笔记