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

 更新时间:2026年02月03日 11:27:55   作者:独断万古他化  
MyBatis-Plus是一个MyBatis的增强工具,提供快速开发单表CRUD操作等功能,通过依赖引入和配置,可以快速创建和使用Mapper接口进行数据库操作,这篇文章通过实例代码介绍MyBatis-Plus注解配置、条件构造器与自定义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依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.7</version>
</dependency>

Spring Boot3依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
    <version>3.5.5</version>
</dependency>

MySQL依赖

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

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

# 数据库连接配置
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文件)

#驱动类名称
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 入门使用

  • 创建实体类,实体类的属性名与表中的字段名一一对应:
  • 编写Mapper接口类

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

BaseMapper包含了很多方法,示例

Mapper接口代码

@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}

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

  1. CRUD单元测试

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

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

@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是如何知道,我们要操作的是哪张表,表里有哪些字段呢?

@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

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

示例:

@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 如何映射实体类字段到数据库表字段。如果实体类字段名遵循驼峰命名规则,并且与数据库表字段名一致,可以省略这个注解。

示例:

@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,可以省略这个注解。

示例:

@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 参数介绍:

  • value
    • 类型:String
    • 默认值""
    • 描述:指定数据库表的主键字段名。如果不设置,MyBatis-Plus 将使用实体类中的字段名作为数据库表的主键字段名。
  • 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):

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:

SELECT id,username,password,age FROM user_info WHERE age = 18 AND username LIKE "%min%"

测试代码:

@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:

UPDATE user_info SET delete_flag=? WHERE age < 20

测试代码:

@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:

DELETE FROM user_info WHERE age = 18

测试代码:

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

}

3.3.2 UpdateWrapper

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

  1. 基础更新

完成SQL:

UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)

测试代码

@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:

UPDATE user_info SET age = age+10 WHERE id IN (1,2,3)

测试代码

@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。

@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相似:

@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查询:

select id,username,password,age FROM user_info WHERE username = "admin"

Mapper

@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);
}

测试代码

@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)

mybatis-plus:
  mapper-locations: "classpath*:/mapper/**.xml" # Mapper.xml

Mapper

    List<UserInfo> queryUserByCustom2(@Param(Constants.WRAPPER) Wrapper<UserInfo> wrapper);

编写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>

测试

@Test
void testQueryUserByCustom2(){
    QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>()
            .eq("username","admin");
    userInfoMapper.queryUserByCustom2(queryWrapper).forEach(System.out::println);
}

到此这篇关于MyBatis-Plus注解配置、条件构造器与自定义SQL的复杂操作实例详解的文章就介绍到这了,更多相关MyBatisPlus注解条件构造器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringMVC返回图片的几种方式(小结)

    SpringMVC返回图片的几种方式(小结)

    这篇文章主要介绍了SpringMVC返回图片的几种方式(小结),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01
  • java socket长连接中解决read阻塞的3个办法

    java socket长连接中解决read阻塞的3个办法

    这篇文章主要介绍了java socket长连接中解决read阻塞的3个办法,本文取了折中的一个方法,并给出代码实例,需要的朋友可以参考下
    2014-08-08
  • 关于ArrayList的动态扩容机制解读

    关于ArrayList的动态扩容机制解读

    这篇文章主要介绍了关于ArrayList的动态扩容机制解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • java中ArrayList与LinkedList对比详情

    java中ArrayList与LinkedList对比详情

    这篇文章主要通过实例对Java中ArrayList与LinkedList进行了对比,需要的朋友可以参考下
    2017-04-04
  • 关于Controller层和Service层的类报错问题及解决方案

    关于Controller层和Service层的类报错问题及解决方案

    这篇文章主要介绍了关于Controller层和Service层的类报错问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • java设计模式:建造者模式之生产线

    java设计模式:建造者模式之生产线

    这篇文章主要介绍了Java设计模式之建造者模式,结合具体实例形式分析了建造者模式的概念、原理、实现方法与相关使用注意事项,需要的朋友可以参考下
    2021-08-08
  • Springboot整合Swagger2后访问swagger-ui.html 404报错问题解决方案

    Springboot整合Swagger2后访问swagger-ui.html 404报错问题解决方案

    这篇文章主要介绍了Springboot整合Swagger2后访问swagger-ui.html 404报错,本文给大家分享两种解决方案,结合实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-06-06
  • ruoyi微服务版本搭建运行方式

    ruoyi微服务版本搭建运行方式

    这篇文章主要介绍了ruoyi微服务版本搭建运行方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • 详解springboot设置cors跨域请求的两种方式

    详解springboot设置cors跨域请求的两种方式

    这篇文章主要介绍了详解springboot设置cors跨域请求的两种方式,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-11-11
  • java IP归属地功能实现详解

    java IP归属地功能实现详解

    前一阵子抖音和微博开始陆续上了IP归属地的功能,引起了众多热议,有大批在国外的老铁们开始"原形毕露",被定位到国内来,那么IP归属到底是怎么实现的呢?那么网红们的归属地到底对不对呢
    2022-07-07

最新评论