【MyBatis-Plus 进阶】注解配置、条件构造器与自定义 SQL的复杂操作详解

文章目录

    • 一、MyBatis-Plus介绍
    • [二、MyBatis-Plus 入门使用](#二、MyBatis-Plus 入门使用)
      • [2.1 依赖引入与配置](#2.1 依赖引入与配置)
      • [2.2 入门使用](#2.2 入门使用)
    • 三、MyBatis-Plus复杂操作
      • [3.1 注解配置](#3.1 注解配置)
        • [3.1.1 @TableName](#3.1.1 @TableName)
        • [3.1.2 @TableField](#3.1.2 @TableField)
        • [3.1.3 @TableId](#3.1.3 @TableId)
      • [3.2 打印日志](#3.2 打印日志)
      • [3.3 条件构造器](#3.3 条件构造器)
        • [3.3.1 QueryWrapper](#3.3.1 QueryWrapper)
        • [3.3.2 UpdateWrapper](#3.3.2 UpdateWrapper)
        • [3.3.3 LambdaQueryWrapper](#3.3.3 LambdaQueryWrapper)
        • [3.3.4 LambdaUpdateWrapper](#3.3.4 LambdaUpdateWrapper)
      • [3.4 自定义SQL](#3.4 自定义SQL)

一、MyBatis-Plus介绍

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

特性

  • 润物无声: 只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑。
  • 效率至上: 只需简单配置,即可快速进行单表 CRUD 操作,从而节省大量时间。
  • 丰富功能: 代码生成、自动分页、逻辑删除、自动填充、拦截器等功能一应俱全。
  • 广泛认可: 连续 5 年获得开源中国年度最佳开源项目殊荣,Github 累计 16K Star。

支持数据库

PostgreSQL, MySQL, MariaDB, Oracle, SQL Server, OceanBase, H2, DB2...

(任何能使用 MyBatis 进行增删改查,并且支持标准 SQL 的数据库应该都在 MyBatis-Plus 的支持范围内)

官网地址:Mybatis-Plus 简化开发

二、MyBatis-Plus 入门使用

Mybatis-Plus操作数据库的步骤:

2.1 依赖引入与配置

  1. 创建springboot工程
  2. 添加MyBatis-Plus和MySQL依赖, 配置数据库连接信息

Spring Boot2依赖

xml 复制代码
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.7</version>
</dependency>

Spring Boot3依赖

xml 复制代码
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
    <version>3.5.5</version>
</dependency>

MySQL依赖

xml 复制代码
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

配置数据库(application.yml文件)

yaml 复制代码
# 数据库连接配置
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

配置数据库(application.properties文件)

properties 复制代码
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=root

2.2 入门使用

  1. 创建实体类,实体类的属性名与表中的字段名一一对应:

  2. 编写Mapper接口类

MybatisPlus提供了一个基础的BaseMapper 接口,已经实现了单表的CRUD,自定义的 Mapper只需要继承这个BaseMapper,就无需自己实现单表CRUD了。

BaseMapper包含了很多方法,示例

Mapper接口代码

java 复制代码
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}

也可以在启动类上添加 @MapperScan ,扫描Mapper文件夹,如下:(二选一即可)

  1. CRUD单元测试

在创建出来的SpringBoot工程中,在src下的test目录下,创建测试类,可以直接使用这个测试类来进行测试。

编写单元测试,测试基本的CRUD功能:

java 复制代码
@SpringBootTest
class MybatisPlusDemoApplicationTests {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    public void testSelect() {
        System.out.println(("----- selectAll method test ------"));
        List<UserInfo> userList = userInfoMapper.selectList(null);
        userList.forEach(System.out::println);
    }
}

运行结果如下

三、MyBatis-Plus复杂操作

3.1 注解配置

MyBatis是如何知道,我们要操作的是哪张表,表里有哪些字段呢?

java 复制代码
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}

UserInfoMapper 在继承BaseMapper 时, 指定了一个泛型, 这个UserInfo就是与数据库表相对应的实体类。MyBatis-Plus会根据这个实体类来推断表的信息。

默认情况下

  1. 表名: 实体类的驼峰表示法转换成蛇形表示法(下划线分割), 作为表名。比如UserInfo -> user_info
  2. 字段: 根据实体类的属性名转换为蛇形表示法作为字段名。比如deleteFlag -> delete_flag
  3. 主键: 默认为id

如果实体类和数据库不是按照上述规则定义。MyBatis-Plus也给我们提供了一些注解,用来标识表的信息。

3.1.1 @TableName

该注解用于指定实体类对应的数据库表名。当实体类名与数据库表名不一致,或者实体类名不是数据库表名的驼峰写法时,可以使用这个注解来明确指定表名。

示例:

java 复制代码
@Data
@TableName("user_info")
public class Userinfo {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}
3.1.2 @TableField

该注解用于标记实体类中的非主键字段,它告诉 MyBatis-Plus 如何映射实体类字段到数据库表字段。如果实体类字段名遵循驼峰命名规则,并且与数据库表字段名一致,可以省略这个注解。

示例:

java 复制代码
@Data
@TableName("user_info")
public class Userinfo {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    @TableField("delete_flag")
    private Integer deleteflag;
    private Date createTime;
    private Date updateTime;
}
3.1.3 @TableId

该注解用于标记实体类中的主键字段。如果你的主键字段名为 id,可以省略这个注解。

示例:

java 复制代码
@Data
@TableName("user_info")
public class Userinfo {
    @TableId("id")
    private Integer userId;
    private String username;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    @TableField("delete_flag")
    private Integer deleteflag;
    private Date createTime;
    private Date updateTime;
}

如果属性名和字段名不一致, 需要在@TableId 指明对应的字段名;属性名和字段一致的情况下, 直接加@TableId 注解就可以。

@TableId 参数介绍:

  1. value
    类型 :String
    默认值""
    描述:指定数据库表的主键字段名。如果不设置,MyBatis-Plus 将使用实体类中的字段名作为数据库表的主键字段名。

  2. type
    类型 :Enum
    默认值 :IdType.NONE
    描述:指定主键的生成策略。

IdType 枚举类型定义

  • IdType.AUTO:使用数据库自增 ID 作为主键。
  • IdType.NONE:无特定生成策略,如果全局配置中有 IdType 相关的配置,则会跟随全局配置。
  • IdType.INPUT:在插入数据前,由用户自行设置主键值。
  • IdType.ASSIGN_ID:自动分配 ID,适用于 Long、Integer、String 类型的主键。默认使用雪花算法通过 IdentifierGenerator 的 nextId 实现。
  • IdType.ASSIGN_UUID:自动分配 UUID,适用于 String 类型的主键。默认实现为 IdentifierGenerator 的 nextUUID 方法。

详情参考网址:注解配置


3.2 打印日志

Mybatis-Plus配置日志如下(application.yml):

yaml 复制代码
mybatis-plus:
  configuration: # 配置打印 MyBatis日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3.3 条件构造器

MyBatis-Plus 提供了一套强大的条件构造器(Wrapper), 用于构建复杂的数据库查询条件。Wrapper 类允许开发者以链式调用的方式构造查询条件, 无需编写繁琐的 SQL 语句, 从而提高开发效率并减少 SQL 注入的风险。

以下是主要的 Wrapper 类及其功能:

  • AbstractWrapper:这是一个抽象基类, 提供了所有 Wrapper 类共有的方法和属性。详细参考官网介绍: 条件构造器
  • QueryWrapper:用于构造查询条件, 在AbstractWrapper的基础上拓展了一个select方法, 允许指定查询字段。
  • UpdateWrapper:用于构造更新条件, 可以在更新数据时指定条件。
  • LambdaQueryWrapper:基于 Lambda 表达式的查询条件构造器, 它通过 Lambda 表达式来引用实体类的属性,从而避免了硬编码字段名。
  • LambdaUpdateWrapper:基于 Lambda 表达式的更新条件构造器, 它允许你使用 Lambda 表达式来指定更新字段和条件,同样避免了硬编码字段名的问题。
3.3.1 QueryWrapper

QueryWrapper并不只用于查询语句, 无论是修改, 删除, 查询, 都可以使用QueryWrapper来构建查询条件。

  1. 查询

完成SQL:

sql 复制代码
SELECT id,username,password,age FROM user_info WHERE age = 18 AND username LIKE "%min%"

测试代码:

java 复制代码
@Test
@Test
    void testQueryWrapper(){
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id","username","password","age")
                .eq("age",18)
                .like("username","min");
        List<UserInfo> userInfos = userInfoMapper.selectList(queryWrapper);
        userInfos.forEach(System.out::println);
    }
  1. 更新

完成SQL:

sql 复制代码
UPDATE user_info SET delete_flag=? WHERE age < 20

测试代码:

java 复制代码
@Test
@Test
    void testUpdateByQueryWrapper(){
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.lt("age",20);
        UserInfo userInfo = new UserInfo();
        userInfo.setDeleteFlag(1);
        userInfoMapper.update(userInfo,queryWrapper);
    }

条件方法说明

  • lt : "less than" 的缩写,表示小于
  • le : "less than or equal to"的缩写, 表示小于等于
  • ge : "greater than or equal to" 的缩写, 表示大于等于
  • gt : "greater than" 的缩写, 表示大于
  • eq : "equals" 的缩写, 表示等于
  • ne : "not equals" 的缩写, 表示不等于
  1. 删除

完成SQL:

sql 复制代码
DELETE FROM user_info WHERE age = 18

测试代码:

java 复制代码
@Test
void testDeleteByQueryWrapper(){
    QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<UserInfo>()
            .eq("age",18);
    userInfoMapper.delete(userInfoQueryWrapper);

}
3.3.2 UpdateWrapper

对于更新,也可以直接使用 UpdateWrapper,在不创建实体对象的情况下,直接设置更新字段和条件。

  1. 基础更新

完成SQL:

sql 复制代码
UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)

测试代码

java 复制代码
@Test
void testUpdateWrapper(){
    UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();

    updateWrapper.set("delete_flag",1).set("age",5).in("id",List.of(2,3,5,8));
    userInfoMapper.update(updateWrapper);
}
  1. 基于SQL更新

完成SQL:

sql 复制代码
UPDATE user_info SET age = age+10 WHERE id IN (1,2,3)

测试代码

java 复制代码
@Test
void testUpdateBySQLUpdateWrapper(){
    UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<UserInfo>()
            .setSql("age = age+10")
            .in("id", List.of(1,2,3));
    userInfoMapper.update(null, updateWrapper);
}
3.3.3 LambdaQueryWrapper

QueryWrapper 和 UpdateWrapper存在一个问题, 就是需要写死字段名, 如果字段名发生变更, 可能会因为测试不到位酿成事故。

MyBatis-Plus 提供了一种基于Lambda表达式的条件构造器, 它通过 Lambda 表达式来引用实体类的属性,从而避免了硬编码字段名,也提高了代码的可读性和可维护性。

  • LambdaQueryWrapper
  • LambdaUpdateWrapper

分别对应上述的QueryWrapper和UpdateWrapper。

java 复制代码
@Test
void testLambdaQueryWrapper(){
    QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();
    queryWrapper.lambda()
            .select(UserInfo::getUsername, UserInfo::getPassword,UserInfo::getAge)
            .eq(UserInfo::getId, 1);
    userInfoMapper.selectList(queryWrapper).forEach(System.out::println);
}
3.3.4 LambdaUpdateWrapper

LambdaUpdateWrapper用法和 LambdaQueryWrapper相似:

java 复制代码
@Test
void testLambdaUpdateByUpdateWrapper(){
    UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<UserInfo>();
    updateWrapper.lambda()
            .set(UserInfo::getDeleteFlag, 0)
            .set(UserInfo::getAge, 5)
            .in(UserInfo::getId, List.of(1,2,3));
    userInfoMapper.update(null, updateWrapper);
}

3.4 自定义SQL

在实际的开发中, MyBatis-Plus提供的操作不能满足所有的实际需求, MyBatis-Plus 也提供了自定义 SQL的功能, 可以利用Wrapper构造查询条件, 再结合Mapper编写SQL。

  • 注:为了使用这一功能, mybatis-plus 版本不低于 3.0.7。

代码示例1

完成下述SQL查询:

sql 复制代码
select id,username,password,age FROM user_info WHERE username = "admin"

Mapper

java 复制代码
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
    @Select("select id,username,password,age FROM user_info ${ew.customSqlSegment}")
    List<UserInfo> queryUserByCustom(@Param(Constants.WRAPPER) Wrapper<UserInfo> wrapper);
}

测试代码

java 复制代码
@Test
void testQueryUserByCustom(){
    QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>()
            .eq("username","admin");
    userInfoMapper.queryUserByCustom(queryWrapper).forEach(System.out::println);

}

注意

  • 参数命名:在自定义 SQL 时, 传递 Wrapper 对象作为参数时, 参数名必须为 ew ,或者使用注解 @Param(Constants.WRAPPER) 明确指定参数为 Wrapper 对象。
  • 使用 ${ew.customSqlSegment}:在 SQL 语句中,使用 ${ew.customSqlSegment} 来引用 Wrapper 对象生成的 SQL 片段。
  • 不支持基于 entity 的 where 语句:自定义 SQL 时,Wrapper 对象不会基于实体类自动生成 where 子句,你需要手动编写完整的 SQL 语句。

代码示例2

MyBatis-Plus 在 MyBatis 的基础上只做增强不做改变, 所以也支持XML的实现方式。上述功能也可以使用XML的方式完成。

配置mapper路径(application.yml)

yaml 复制代码
mybatis-plus:
  mapper-locations: "classpath*:/mapper/**.xml" # Mapper.xml

Mapper

java 复制代码
    List<UserInfo> queryUserByCustom2(@Param(Constants.WRAPPER) Wrapper<UserInfo> wrapper);

编写XML

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bite.mybatis.plus.mapper.UserInfoMapper">

    <select id="queryUserByCustom2" resultType="com.bite.mybatis.plus.entity.UserInfo">
        select id,username,password,age FROM user_info ${ew.customSqlSegment}
    </select>

</mapper>

测试

java 复制代码
@Test
void testQueryUserByCustom2(){
    QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>()
            .eq("username","admin");

    userInfoMapper.queryUserByCustom2(queryWrapper).forEach(System.out::println);
}
相关推荐
瀚高PG实验室14 小时前
通过数据库日志获取数据库中的慢SQL
数据库·sql·瀚高数据库
阳光九叶草LXGZXJ15 小时前
达梦数据库-学习-47-DmDrs控制台命令(LSN、启停、装载)
linux·运维·数据库·sql·学习
马猴烧酒.20 小时前
【JAVA数据传输】Java 数据传输与转换详解笔记
java·数据库·笔记·tomcat·mybatis
ruxshui20 小时前
Python多线程环境下连接对象的线程安全管理规范
开发语言·数据库·python·sql
Mr_Xuhhh20 小时前
MySQL数据表操作全解析:从创建到管理
数据库·sql·oracle
阳光九叶草LXGZXJ21 小时前
达梦数据库-学习-50-分区表指定分区清理空洞率(交换分区方式)
linux·运维·数据库·sql·学习
Apple_羊先森21 小时前
ORACLE数据库巡检SQL脚本--4、检查锁阻塞
数据库·sql·oracle
麦聪聊数据1 天前
利用SQL2API模式重构微服务中的数据查询层
数据库·sql·低代码·微服务·架构
Aloudata1 天前
数据工程实践:智能制造企业如何通过NoETL指标平台为数据资产“瘦身”,实现TCO最优?
sql·数据分析·etl·指标平台