一、MyBatis-Flex 简介
1.1 什么是 MyBatis-Flex
MyBatis-Flex 是一款基于 MyBatis 的轻量级增强框架,旨在简化数据库操作、提升开发效率,同时保留 MyBatis 原生灵活性与高性能优势。它并非替代 MyBatis,而是通过增强 API、优化架构设计,解决 MyBatis 单表操作繁琐、查询条件构建复杂等问题,且全程无第三方依赖,稳定性与自主性更强。
与同类框架相比,MyBatis-Flex 以"轻量、灵活、高性能"为核心定位:无 MyBatis 拦截器、无 SQL 解析环节,性能较传统增强框架提升 5-10 倍以上;同时支持多表查询、逻辑删除、数据脱敏等企业级特性,兼顾快速开发与复杂业务场景需求。
1.2 与 MyBatis/MyBatis-Plus 的区别
| 特性 | MyBatis | MyBatis-Plus | MyBatis-Flex |
|---|---|---|---|
| 核心定位 | 原生 ORM,侧重 SQL 与代码分离 | MyBatis 增强,功能全面 | 轻量增强,兼顾性能与灵活 |
| 第三方依赖 | 无 | 依赖 hutool 等工具包 | 仅依赖 MyBatis,无其他依赖 |
| 性能表现 | 原生高效 | 拦截器模式有性能损耗 | 无拦截器、无 SQL 解析,性能最优 |
| 特色功能 | 原生 SQL 控制 | 代码生成、条件构造器 | 字段权限、数据脱敏、多租户原生支持 |
二、环境搭建(Spring Boot 集成)
本节以 Spring Boot 2.x + MySQL 为例,手把手教你完成 MyBatis-Flex 集成,Spring Boot 3.x 仅需调整依赖名称,操作一致。
2.1 前提条件
-
JDK 8+(Spring Boot 3.x 需 JDK 17+)
-
熟悉 Spring Boot 基础配置与 Maven/Gradle 构建工具
-
已安装 MySQL 数据库(5.7+)
2.2 创建数据库表
首先创建测试表 tb_account,并插入测试数据:
sql
CREATE TABLE IF NOT EXISTS `tb_account` (
`id` INTEGER PRIMARY KEY auto_increment COMMENT '主键ID',
`user_name` VARCHAR(100) NOT NULL COMMENT '用户名',
`age` INTEGER COMMENT '年龄',
`birthday` DATETIME COMMENT '生日',
`is_deleted` TINYINT DEFAULT 0 COMMENT '逻辑删除标识(0-未删,1-已删)',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
) COMMENT '用户账户表';
INSERT INTO tb_account(user_name, age, birthday)
VALUES ('张三', 18, '2020-01-11'),
('李四', 19, '2021-03-21'),
('王五', 22, '2019-07-05');
2.3 添加 Maven 依赖
在 Spring Boot 项目的pom.xml 中添加以下依赖:
xml
<dependencies/>
<!-- MyBatis-Flex Spring Boot 启动器 -->
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-spring-boot-starter</artifactId/>
<version/>1.11.4</version/> <!-- 建议使用最新稳定版 -->
</dependency/>
<!-- MySQL 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency/>
<!-- 数据库连接池(HikariCP,Spring Boot 默认) -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency/>
<!-- Lombok 简化实体类(可选,推荐) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency/>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
提示:若使用 Spring Boot 3.x,需将 mybatis-flex-spring-boot-starter 替换为 mybatis-flex-spring-boot3-starter。
2.4 配置数据源与 MyBatis-Flex
在 application.yml 中配置数据源和 MyBatis-Flex 基础参数:
yaml
spring:
# 数据源配置
datasource:
url: jdbc:mysql://localhost:3306/flex_test?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
username: root
password: 12345678
driver-class-name: com.mysql.cj.jdbc.Driver
# MyBatis-Flex 配置(可选,默认已适配大部分场景)
mybatis-flex:
# 实体类扫描路径
entity-scan: com.mybatisflex.test.entity
# Mapper 接口扫描路径(也可通过 @MapperScan 注解配置)
mapper-locations: classpath:mappers/**/*.xml
# 开启 SQL 日志打印(开发环境推荐开启)
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
2.5 配置启动类
在 Spring Boot 启动类上添加 @MapperScan 注解,扫描 Mapper 接口所在包:
java
package com.mybatisflex.test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.mybatisflex.test.mapper") // Mapper 接口路径
public class MybatisFlexTestApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisFlexTestApplication.class, args);
}
}
三、基础用法实战
3.1 编写实体类(Entity)
使用 MyBatis-Flex 注解映射数据库表与字段,支持主键策略、逻辑删除、字段填充等配置:
java
package com.mybatisflex.test.entity;
import com.mybatisflex.annotation.*;
import lombok.Data;
import java.util.Date;
@Data // Lombok 注解,自动生成 getter/setter
@Table("tb_account") // 映射数据库表名
@TableLogic(value = "0", deletedValue = "1") // 逻辑删除:未删0,已删1
public class Account {
// 主键,自增策略
@Id(keyType = KeyType.Auto)
private Long id;
// 字段名与数据库一致,可省略 @Column
private String userName;
private Integer age;
private Date birthday;
// 逻辑删除字段,与 @TableLogic 配合使用
private Integer isDeleted;
// 自动填充创建时间(插入时触发)
@Column(fill = FillInsert.class)
private Date createTime;
}
核心注解说明:
-
@Table:指定实体类对应数据库表名,支持逻辑删除全局配置。 -
@Id:标识主键,keyType支持自增(Auto)、UUID、雪花算法等。 -
@Column:配置字段属性,fill支持插入/更新时自动填充。
3.2 编写 Mapper 接口
Mapper 接口继承 MyBatis-Flex 提供的 BaseMapper,即可获得全套单表 CRUD 方法,无需编写 XML 或注解:
java
package com.mybatisflex.test.mapper;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.test.entity.Account;
import org.springframework.stereotype.Repository;
// @Repository 注解用于 Spring 扫描管理
@Repository
public interface AccountMapper extends BaseMapper<Account> {
// 无需额外编写方法,BaseMapper 已提供全套单表操作
}
BaseMapper核心方法包括:insert(新增)、update(更新)、deleteById(按ID删除)、selectById(按ID查询)、selectList(查询列表)等。
3.3 测试单表 CRUD 操作
编写单元测试,验证基础 CRUD 功能,注入 AccountMapper 即可调用方法:
java
package com.mybatisflex.test;
import com.mybatisflex.test.entity.Account;
import com.mybatisflex.test.mapper.AccountMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Date;
import java.util.List;
@SpringBootTest
public class AccountMapperTest {
@Autowired
private AccountMapper accountMapper;
// 新增测试
@Test
public void testInsert() {
Account account = new Account();
account.setUserName("赵六");
account.setAge(25);
account.setBirthday(new Date());
// 调用 BaseMapper 自带方法
int rows = accountMapper.insert(account);
System.out.println("新增行数:" + rows + ",新增ID:" + account.getId());
}
// 按ID查询测试
@Test
public void testSelectById() {
Account account = accountMapper.selectById(1L);
System.out.println("查询结果:" + account);
}
// 条件查询测试
@Test
public void testSelectList() {
// 使用 QueryWrapper 构建查询条件
QueryWrapper queryWrapper = QueryWrapper.create()
.where(Account::getAge).gt(18) // 年龄大于18
.and(Account::getUserName).like("张"); // 用户名包含"张"
List<Account> accounts = accountMapper.selectListByQuery(queryWrapper);
System.out.println("条件查询结果:" + accounts);
}
// 更新测试
@Test
public void testUpdate() {
Account account = new Account();
account.setId(1L);
account.setAge(19); // 修改年龄
int rows = accountMapper.update(account);
System.out.println("更新行数:" + rows);
}
// 逻辑删除测试(实际执行 UPDATE,而非 DELETE)
@Test
public void testDeleteById() {
int rows = accountMapper.deleteById(2L);
System.out.println("删除行数:" + rows);
}
}
四、核心特性详解
4.1 灵活的 QueryWrapper 条件构造器
MyBatis-Flex 提供的 QueryWrapper 支持链式调用,可构建复杂查询条件,包括多表关联、排序、分页等,且语法简洁易懂:
java
// 1. 多条件组合查询
QueryWrapper queryWrapper = QueryWrapper.create()
.select(Account::getId, Account::getUserName, Account::getAge) // 只查询指定字段
.from(Account.class)
.where(Account::getAge).between(18, 30) // 年龄在18-30之间
.and(Account::getUserName).notLike("李") // 排除用户名含"李"的记录
.orderBy(Account::getCreateTime).desc(); // 按创建时间倒序
// 2. 分页查询(第1页,每页10条)
Page<Account> page = accountMapper.paginate(1, 10, queryWrapper);
System.out.println("总条数:" + page.getTotalRows());
System.out.println("分页数据:" + page.getRecords());
// 3. 多表关联查询(示例:关联订单表,查询用户及对应订单数)
QueryWrapper joinQuery = QueryWrapper.create()
.select(Account::getId, Account::getUserName)
.select("COUNT(order.id) as order_count")
.from(Account.class)
.leftJoin(Order.class).on(Account::getId, Order::getAccountId)
.groupBy(Account::getId)
.having("order_count > 0");
4.2 批量操作优化
MyBatis-Flex 提供高效批量插入/更新方法,底层优化 SQL 执行效率,避免循环单条操作的性能问题:
java
// 批量插入
@Test
public void testInsertBatch() {
List<Account/> accountList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
Account account = new Account();
account.setUserName("批量用户" + i);
account.setAge(20 + i);
account.setBirthday(new Date());
accountList.add(account);
}
// 批量插入,返回成功行数
int rows = accountMapper.insertBatch(accountList);
System.out.println("批量插入行数:" + rows);
}
// 批量更新(按ID更新)
@Test
public void testUpdateBatch() {
List<Account> accountList = accountMapper.selectListByQuery(QueryWrapper.create().where(Account::getAge).lt(20));
accountList.forEach(account -> account.setAge(20)); // 统一将年龄改为20
int rows = accountMapper.updateBatch(accountList);
System.out.println("批量更新行数:" + rows);
}
4.3 数据脱敏与字段权限控制
4.3.1 数据脱敏
通过 @DataMask 注解实现字段脱敏,支持姓名、手机号、邮箱等常见场景,查询时自动脱敏,不影响数据库存储:
java
import com.mybatisflex.annotation.DataMask;
import com.mybatisflex.annotation.DataMaskType;
public class Account {
// 其他字段省略...
// 姓名脱敏:保留姓氏,名字替换为*(如"张三"→"张*")
@DataMask(type = DataMaskType.NAME)
private String userName;
// 手机号脱敏:保留前3位和后4位(如"13800138000"→"138****8000")
@DataMask(type = DataMaskType.MOBILE)
private String phone;
}
4.3.2 字段权限控制
通过 @Table 注解的 fieldPermission 属性,基于角色控制字段访问权限,适用于多角色场景:
java
@Table(value = "tb_account", fieldPermission = {
@FieldPermission(role = "admin", columns = {"*"}), // 管理员可查看所有字段
@FieldPermission(role = "user", columns = {"id", "userName", "age"}) // 普通用户仅查看部分字段
})
public class Account {
// 字段定义省略...
}
使用时需设置当前角色,查询时自动过滤无权限字段:
java
// 设置当前角色为普通用户
QueryWrapper queryWrapper = QueryWrapper.create()
.setRole("user")
.where(Account::getAge).gt(18);
List<Account> accounts = accountMapper.selectListByQuery(queryWrapper);
// 返回结果仅包含 id、userName、age 字段
4.4 多租户支持
MyBatis-Flex 原生支持多租户,通过配置 TenantHandler 自动为查询、新增、更新操作添加租户条件,无需手动拼接:
java
// 1. 实现 TenantHandler 接口
public class MyTenantHandler implements TenantHandler {
// 租户ID字段名(数据库表中需包含该字段,如 tenant_id)
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
// 获取当前租户ID(实际场景从上下文获取,如登录用户信息)
@Override
public Object getTenantId() {
return SecurityUtils.getCurrentTenantId(); // 自定义方法,获取当前租户ID
}
}
// 2. 配置多租户(全局生效)
@Configuration
public class MyBatisFlexConfig {
@Bean
public MyBatisFlexCustomizer myBatisFlexCustomizer() {
return config -> {
config.setTenantHandler(new MyTenantHandler());
};
}
}
配置后,所有操作自动添加 tenant_id = 当前租户ID 条件,无需修改现有代码,实现租户数据隔离。
五、高级配置与最佳实践
5.1 自定义 SQL 与 XML 映射
MyBatis-Flex 支持原生 MyBatis XML 映射,适合复杂 SQL 场景,可与增强功能混用。例如,在 AccountMapper.xml 中编写自定义 SQL:
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.mybatisflex.test.mapper.AccountMapper"/>
<!-- 自定义查询:查询指定年龄段的用户数量 -->
<select id="countByAgeRange" resultType="java.lang.Integer">
SELECT COUNT(*) FROM tb_account
WHERE age BETWEEN #{minAge} AND #{maxAge}
AND is_deleted = 0
</select>
</mapper>
在 Mapper 接口中添加对应方法:
java
public interface AccountMapper extends BaseMapper<Account> {
// 自定义方法,与 XML 中 id 对应
Integer countByAgeRange(@Param("minAge") Integer minAge, @Param("maxAge") Integer maxAge);
}
5.2 性能优化建议
-
批量操作优先使用
insertBatch/updateBatch,替代循环单条操作,减少数据库连接次数。 -
复杂查询优先使用 XML 自定义 SQL,简单查询用
QueryWrapper,平衡开发效率与性能。 -
启用 MyBatis 二级缓存(针对静态数据),减少重复查询:在 Mapper 接口添加
@CacheNamespace注解。 -
忽略无需持久化的字段,通过
@Column(ignore = true)标注,避免多余字段参与 SQL 构建。
5.3 常见问题排查
-
字段映射失败 :检查实体类注解
@Table、@Column是否正确,数据库字段名与实体类字段名是否一致(可开启 SQL 日志排查生成的 SQL)。 -
逻辑删除不生效 :确保实体类添加
@TableLogic注解,且逻辑删除字段类型与配置值一致(如 TINYINT 对应 0/1)。 -
多租户条件未添加 :检查
TenantHandler实现是否正确,当前租户 ID 是否能正常获取,确保配置类被 Spring 扫描。
六、总结
MyBatis-Flex 作为一款轻量级 MyBatis 增强框架,既保留了原生 MyBatis 的灵活性与高性能,又通过简洁的 API、丰富的企业级特性,大幅降低了日常开发工作量。其无第三方依赖、无性能损耗的设计,使其在中小型项目快速开发与大型项目复杂场景中均能适用。
对于从 MyBatis 迁移的项目,MyBatis-Flex 可平滑集成,无需修改现有 XML 与 SQL;对于新项目,其 QueryWrapper、批量操作、多租户等特性,能有效提升开发效率,同时保持对 SQL 的绝对控制。建议在实际开发中根据业务场景灵活运用其增强功能,平衡开发效率与系统性能。
更多细节可参考官方文档:https://mybatis-flex.com/。