一.简介
做 Java 开发的同学基本都离不开 MyBatis。
MyBatis 的灵活性确实很强,但写 XML 配置文件有时候确实比较繁琐;后来出现的 MyBatis-Plus 在单表 CRUD 方面体验很好,不过一旦涉及复杂的多表查询,还是需要手写 SQL。
最近做项目使用了一下 MyBatis-Flex,感觉确实比较惊喜:
既保留了 MyBatis 的灵活性和高性能,又在单表操作和多表 Join 上提供了非常优雅的写法,而且代码提示非常友好。
这篇文章简单介绍一下 MyBatis-Flex 的基础使用。
二.APT 与强类型 SQL介绍
MyBatis-Flex 的一个核心特点是 APT(编译期注解处理器)。
我们经常使用的Lombok就是基于APT实现的 Lombok的@Data注解就是利用APT 在编译阶段生成getter,setter代码。
传统 MyBatis 在写查询条件时,经常需要写字符串形式的字段名,例如:
@Select("SELECT * FROM user WHERE user_name = #{userName}")这种方式的问题是:
-
字段名是字符串,没有代码提示
-
容易拼写错误
-
数据库字段修改时,代码不会在编译期报错
而 MyBatis-Flex 的 APT 会在编译时自动生成 表定义类(TableDef)
例如: 你有一个User的实体类,在编译时就会生成UserTableDef
这样写查询条件时就可以变成:
QueryWrapper query = QueryWrapper.create() .where(USER.USER_NAME.eq(userName));优势很明显:
-
idea 自动提示字段
-
类型安全
-
字段变更时编译期就能发现问题
三.搭建开发环境
我这里的演示环境是:
-
Java 21
-
Spring Boot 4
-
MyBatis-Flex 1.11.6
1.依赖导入
核心 pom.xml 配置如下:
<properties> <java.version>21</java.version> <mybatis-flex.version>1.11.6</mybatis-flex.version></properties>
<dependencies> <dependency> <!--flex的配置--> <groupId>com.mybatis-flex</groupId> <artifactId>mybatis-flex-spring-boot4-starter</artifactId> <version>${mybatis-flex.version}</version> </dependency>
<!--jdbc配置,springboot4因 stater 提供的 spring-boot-autoconfigure , 不再默认包含 jdbc(datasource) 的 autoconfigure, 需要添加依赖 spring-boot-starter-jdbc--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency></dependencies>
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.13.0</version> <configuration> <annotationProcessorPaths> <path> <!--flex的apt配置--> <groupId>com.mybatis-flex</groupId> <artifactId>mybatis-flex-processor</artifactId> <version>${mybatis-flex.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins></build>如果使用 IDEA,需要开启 注解处理器

2.配置文件和数据库配置
我这里使用的是mysql 8.0 配置文件:
spring: datasource: url: jdbc:mysql://localhost:3306/flex-demo?useUnicode=true&characterEncoding=utf-8&useSSL=false username: 你的用户名 password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-flex: configuration: # 开启控制台 SQL 打印 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl这里创建两个简单的表:
# 创建数据库CREATE DATABASE IF NOT EXISTS flex_db;
# 用户表CREATE TABLE user( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50), age INT);
# 用户详情表CREATE TABLE user_detail( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT, address VARCHAR(100), phone VARCHAR(20));user表:存储用户的基础信息user_detail表:存储用户的详细信息- 两张表通过
user_detail.user_id与user.id建立关联关系
3.实体类和VO
实体类只需要使用 @Table 和 @Id 注解即可:
@Table用于标注实体类对应的数据库表名@Id指定主键字段
@Data@Table("user")public class User {
@Id private Long id;
private String username;
private Integer age;}@Data@Table("user_detail")public class UserDetail {
@Id private Long id;
private Long userId;
private String address;
private String phone;}VO用于连表查询返回
import lombok.Data;
@Datapublic class UserVO { // 来自 user 表的字段 private Long id; private String username; private Integer age;
// 来自 user_detail 表的字段 private String address; private String phone;}4.Mapper 接口
MyBatis-Flex 提供了 BaseMapper,继承后即可获得大量基础 CRUD 方法。
import com.mybatisflex.core.BaseMapper;import org.apache.ibatis.annotations.Mapper;
@Mapperpublic interface UserMapper extends BaseMapper<User> {
}@Mapperpublic interface UserDetailMapper extends BaseMapper<UserDetail> {
}常见的方法
| 方法 | 功能 |
|---|---|
| insert | 插入数据 |
| deleteById | 根据主键删除 |
| update | 根据主键更新 |
| selectById | 根据主键查询 |
| selectList | 查询列表 |
5.添加源代码根目录
没有添加之前,代码会因为找不到 Flex 生成的 TableDef 类无法导包而爆红。这是因为 IDEA 默认不会去扫描 target 目录下的代码。

解决办法:
在左侧目录树中,找到 target/generated-sources/annotations 文件夹(如图二)。
右键点击 annotations 文件夹。
选择 将目录标记为 -> 源代码更根目录。
设置完成后,文件夹图标会变色,IDEA 建立索引后代码就可以正常导包了。
四.查询示例
1.单表查询示例
查询 年龄大于 18 岁的用户:
public void testSingleTableQuery() { // 1. 创建查询条件包装器 (QueryWrapper) QueryWrapper queryWrapper = QueryWrapper.create() // USER: 是 MyBatis-Flex 自动生成的类,代表 `user` 表 // AGE: 代表 `user` 表里的 `age` 字段 // gt(18):gt 是 "greater than" 的缩写,意思是“大于 (>) 18” // 组合起来相当于 SQL 里的:WHERE age > 18 .where(USER.AGE.gt(18));
// 2. 调用 userMapper 执行查询,返回值是一个 List,里面装的是 User 实体类 List<User> adultUsers = userMapper.selectListByQuery(queryWrapper);MyBatis-Flex 实际生成的 SQL 类似:
SELECT *FROM userWHERE age > 18;2.多表 Join 查询
查询 用户及其详情信息:
public void testJoinTableQuery() { // 1. 创建查询条件包装器,构建 Join 查询的 SQL QueryWrapper queryWrapper = QueryWrapper.create() .select() // 代表查询这两张表的所有字段 (相当于 SELECT *) .from(USER) // 主表是 user 表 (相当于 FROM user)
// leftJoin: 代表左连接 user_detail 表 (相当于 LEFT JOIN user_detail) .leftJoin(USER_DETAIL)
// on: 定义连表的关联条件 // USER.ID.eq(...) : eq 是 "equals" 的缩写,意思是“等于 (=)” // 组合起来相当于 SQL 里的:ON user.id = user_detail.user_id .on(USER.ID.eq(USER_DETAIL.USER_ID))
// where: 筛选条件 // ge(20) : ge 是 "greater than or equal to" 的缩写,意思是“大于等于 (>=) 20” // 组合起来相当于 SQL 里的:WHERE user.age >= 20 .where(USER.AGE.ge(20));
// 2. 执行查询并转换结果类型 // selectListByQueryAs 的第二个参数 UserVO.class 非常关键 // 框架会自动把查出来的字段(如 username, address, phone)映射到 UserVO 对应的属性里 List<UserVO> userVOList = userMapper.selectListByQueryAs(queryWrapper, UserVO.class);对应生成的 SQL 类似:
SELECT *FROM userLEFT JOIN user_detailON user.id = user_detail.user_idWHERE user.age >= 20;eq = Equal (等于 =)
ne = Not Equal (不等于 !=)
gt = Greater Than (大于 >)
ge = Greater than or Equal (大于等于 >=)
lt = Less Than (小于 <)
le = Less than or Equal (小于等于 <=)
五.总结
本文只介绍了 MyBatis-Flex 的基本使用流程以及可能遇到的问题,更多高级功能和详细用法可参考官方文档进一步学习。
部分信息可能已经过时