MyBatis-Flex 完整使用指南
一、环境准备
1. Maven 依赖
xml
<dependencies>
<!-- MyBatis-Flex 核心依赖 -->
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-spring-boot-starter</artifactId>
<version>1.8.0</version>
</dependency>
<!-- 数据库驱动(以 MySQL 为例) -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
<!-- Lombok(可选) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
二、完整配置流程
1. 数据源配置 (application.yml)
yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# MyBatis-Flex 高级配置
mybatis-flex:
# 是否打印 SQL(开发环境建议开启)
print-sql: true
# 全局配置
global-config:
# 逻辑删除配置
logic-delete:
logic-delete-value: 1 # 已删除值
logic-not-delete-value: 0 # 未删除值
# 多租户配置
tenant-config:
ignore-tables: sys_config, sys_log # 忽略租户过滤的表
# 字段安全类型(脱敏/加密)
column-security:
# 全局加密密钥(可覆盖)
aes-key: "my-secret-key-123"
2. 实体类配置
java
@Table("tb_account")
@Data
public class Account {
@Id(keyType = KeyType.Auto)
private Long id;
@Column("user_name")
private String userName;
private Integer age;
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
@Column(onUpdateValue = "now()")
private LocalDateTime updateTime;
// 逻辑删除字段(0:正常,1:删除)
@Column(logicDelete = true)
private Integer isDeleted;
// 多租户字段
@Column(tenantId = true)
private Long tenantId;
// 加密字段(手机号)
@Column(cryptoType = CryptoType.AES)
private String mobile;
// 脱敏字段(银行卡号)
@Column(maskType = MaskType.BANK_CARD)
private String bankCard;
// 乐观锁字段
@Column(version = true)
private Integer version;
}
3. Mapper 接口
java
@Mapper
public interface AccountMapper extends BaseMapper<Account> {
// 自定义SQL方法示例
@Select("SELECT * FROM tb_account WHERE age > #{minAge}")
List<Account> selectByMinAge(@Param("minAge") int minAge);
}
4. Service 层实现
java
@Service
public class AccountService extends ServiceImpl<AccountMapper, Account> {
// 自定义业务方法
public List<Account> findAdults() {
return queryChain()
.select(Account::getId, Account::getUserName)
.where(Account::getAge).ge(18)
.list();
}
}
三、核心 API 完整使用
1. 条件构造器(QueryWrapper)
java
// 基础查询
QueryWrapper query = QueryWrapper.create()
.select(ACCOUNT.ID, ACCOUNT.USER_NAME, ACCOUNT.AGE)
.from(ACCOUNT)
.where(ACCOUNT.AGE.between(18, 60))
.and(ACCOUNT.USER_NAME.like("张%"))
.orderBy(ACCOUNT.AGE.desc(), ACCOUNT.ID.asc())
.limit(10);
// 联表查询(带别名)
QueryWrapper query = QueryWrapper.create()
.select(ACCOUNT.ID, ORDER.ORDER_NO, ORDER.AMOUNT)
.from(ACCOUNT.as("a"))
.leftJoin(ORDER).as("o").on(ACCOUNT.ID.eq(ORDER.ACCOUNT_ID))
.where(ORDER.CREATE_TIME.ge(LocalDate.now().minusMonths(1)))
.groupBy(ACCOUNT.ID)
.having(sum(ORDER.AMOUNT).gt(10000));
// 子查询
QueryWrapper subQuery = QueryWrapper.create()
.select(ORDER.ACCOUNT_ID)
.from(ORDER)
.where(ORDER.STATUS.eq(1));
QueryWrapper mainQuery = QueryWrapper.create()
.select()
.from(ACCOUNT)
.where(ACCOUNT.ID.in(subQuery))
.and(ACCOUNT.TENANT_ID.eq(123));
// Lambda 表达式
LambdaQueryWrapper<Account> lambdaQuery = LambdaQueryWrapper.create()
.select(Account::getId, Account::getUserName)
.eq(Account::getAge, 25)
.likeRight(Account::getUserName, "张")
.orderByDesc(Account::getCreateTime);
2. 更新操作(UpdateWrapper)
java
// 条件更新
UpdateWrapper update = UpdateWrapper.create()
.set(ACCOUNT.AGE, ACCOUNT.AGE.add(1))
.set(ACCOUNT.UPDATE_TIME, LocalDateTime.now())
.where(ACCOUNT.LAST_LOGIN_TIME.lt(LocalDate.now().minusYears(1)));
// 实体更新
Account account = new Account();
account.setStatus(2);
UpdateWrapper update = UpdateWrapper.of(account)
.where(ACCOUNT.STATUS.eq(1).and(ACCOUNT.AGE.lt(18)));
// Lambda 更新
LambdaUpdateWrapper<Account> lambdaUpdate = LambdaUpdateWrapper.create()
.set(Account::getAge, 30)
.set(Account::getUpdateTime, LocalDateTime.now())
.eq(Account::getId, 1001);
3. 分页与聚合
java
// 分页查询
Page<Account> page = Page.of(1, 20); // 第1页,每页20条
QueryWrapper query = QueryWrapper.create()
.where(ACCOUNT.AGE.ge(18))
.orderBy(ACCOUNT.CREATE_TIME.desc());
Page<Account> result = mapper.paginate(page, query);
// 分页结果处理
List<Account> records = result.getRecords();
long total = result.getTotalRow();
long totalPages = result.getTotalPage();
// 聚合查询
QueryWrapper aggQuery = QueryWrapper.create()
.select(
ACCOUNT.DEPT_ID,
count().as("emp_count"),
avg(ACCOUNT.SALARY).as("avg_salary"),
max(ACCOUNT.SALARY).as("max_salary")
)
.groupBy(ACCOUNT.DEPT_ID)
.having(avg(ACCOUNT.SALARY).gt(10000));
4. 事务管理
java
// 声明式事务
@Transactional(rollbackFor = Exception.class)
public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
// 扣减转出账户
UpdateWrapper deduct = UpdateWrapper.create()
.setRaw(ACCOUNT.BALANCE, "balance - ?", amount)
.where(ACCOUNT.ID.eq(fromId));
accountMapper.updateByQuery(deduct);
// 增加转入账户
UpdateWrapper add = UpdateWrapper.create()
.setRaw(ACCOUNT.BALANCE, "balance + ?", amount)
.where(ACCOUNT.ID.eq(toId));
accountMapper.updateByQuery(add);
// 记录交易流水
transactionService.logTransfer(fromId, toId, amount);
}
// 编程式事务
public void batchImport(List<Account> accounts) {
Transaction.tx(() -> {
for (Account account : accounts) {
if (account.getAge() < 18) {
throw new RuntimeException("未成年账户禁止导入");
}
accountMapper.insert(account);
}
return true;
});
}
5. 高级特性
java
// 1. 逻辑删除(自动添加条件)
accountMapper.deleteById(1L); // → UPDATE SET is_deleted=1 WHERE id=1
// 2. 多租户过滤(自动添加租户ID条件)
List<Account> list = accountMapper.selectAll();
// → SELECT * FROM tb_account WHERE tenant_id=当前租户ID
// 3. 字段加密/解密(自动处理)
Account account = accountMapper.selectOneById(1L);
System.out.println(account.getMobile()); // 自动解密 → 13800138000
// 4. 数据脱敏
Account account = accountMapper.selectOneById(1L);
System.out.println(account.getBankCard()); // → 622202******1234
// 5. 乐观锁更新
Account account = accountMapper.selectOneById(1L);
account.setBalance(account.getBalance() + 100);
accountMapper.update(account);
// → UPDATE ... WHERE id=1 AND version=旧版本
6. 工具类使用
java
// Db 工具类快速操作
Db.insert("account", "id,user_name,age", 1001, "张三", 30);
Db.updateById("account", "age", 31, 1001);
List<Account> list = Db.selectAllByCondition(Account.class, "age > ?", 18);
// 批量操作
List<Account> accounts = ...;
Db.executeBatch(accounts, 1000, (mapper, account) -> {
mapper.insert(account);
});
// SQL 工具
String inSql = SqlUtil.buildInCondition("id", Arrays.asList(1,2,3));
// → id IN (1,2,3)
String safeSql = SqlUtil.escapeSql("SELECT * FROM user WHERE name='admin' OR 1=1");
// → 防止 SQL 注入的安全处理
四、MyBatis-Flex vs MyBatis-Plus 终极对比
特性维度 | MyBatis-Flex | MyBatis-Plus | 优势分析 |
---|---|---|---|
架构设计 | 纯 Java 实现,无第三方依赖 (500KB+) | 依赖 Javassist 等工具 | Flex 更轻量,启动更快 |
多表查询 | 原生支持 JOIN/UNION/子查询 | 需自定义 XML 或使用插件 | Flex 复杂查询开发效率高 5 倍+ |
性能表现 | 基准测试快 5-10 倍 | 中等水平 | Flex 高并发场景优势明显 |
条件构造器 | 链式调用,SQL 风格 | 方法名拼接 | Flex 更直观,学习成本低 |
Lambda 支持 | 全 Lambda 类型推断 | 部分场景需手动指定类型 | Flex 类型安全更好 |
注解功能 | 30+ 种注解覆盖企业级需求 | 基础注解 | Flex 功能更全面 |
字段加密 | 原生支持 AES/RSA 等算法 | 需自定义实现 | Flex 开箱即用 |
多租户 | 注解配置,支持忽略表 | 需插件配置 | Flex 配置更简洁 |
SQL 生成 | 智能识别数据库方言 | 基础分页支持 | Flex 适配性更好 |
代码生成器 | 高度可定制,支持多种模板 | 基础生成功能 | Flex 扩展性更强 |
社区生态 | 快速增长,文档完善 | 成熟稳定,社区庞大 | Plus 更成熟,Flex 更活跃 |
学习曲线 | 陡峭(功能强大) | 平缓(简单易用) | 新项目选 Flex,老项目选 Plus |
五、总结与最佳实践
MyBatis-Flex 核心价值:
- 💨 极致性能:比传统 ORM 框架快 5-10 倍,适合高并发场景
- 🧩 轻量灵活:无冗余依赖,功能模块可插拔
- 🚀 开发效率:复杂 SQL 开发效率提升 3 倍以上
- 🛡️ 企业级特性:多租户/字段加密/数据脱敏开箱即用
- 📊 智能优化:自动识别数据库方言,智能 SQL 优化
最佳实践场景:
- 新项目选型:特别是微服务架构下的新系统
- 金融级应用:对数据安全和性能有高要求的系统
- 复杂业务系统:需要大量复杂 SQL 的业务(如 ERP、CRM)
- 高并发场景:电商、社交等需要处理高并发的系统
- 多租户 SaaS:需要灵活租户管理的云应用
迁移建议:
- MyBatis → MyBatis-Flex:直接引入,兼容性好
- MyBatis-Plus → MyBatis-Flex :
- 保留实体类和 Mapper 接口
- 逐步替换条件构造器代码
- 利用 Flex 的兼容模式平滑过渡
- 其他 ORM 框架 :
- 保留数据库设计
- 重新生成实体类和 Mapper
- 业务层逐步重写
终极建议:
- 追求 性能 和 灵活性 → 选择 MyBatis-Flex
- 需要 稳定 和 简单 CRUD → 选择 MyBatis-Plus
- 金融/电商 等高性能场景 → 强烈推荐 MyBatis-Flex
MyBatis-Flex 代表了 MyBatis 增强框架的新方向,在保持轻量级的同时提供了企业级功能,是现代化 Java 应用开发的理想选择。