【还在使用MyBatis-Plus?更强大的来了】MyBatis-Flex 完整使用指南
MyBatis-Flex 完整使用指南
一、环境准备
1. Maven 依赖
<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)
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. 实体类配置
@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 接口
@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 层实现
@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)
// 基础查询
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)
// 条件更新
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. 分页与聚合
// 分页查询
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. 事务管理
// 声明式事务
@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. 高级特性
// 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. 工具类使用
// 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 应用开发的理想选择。
【还在使用MyBatis-Plus?更强大的来了】MyBatis-Flex 完整使用指南的更多相关文章
- 比 Navicat 还要好用、功能更强大的工具!
DBeaver 是一个基于 Java 开发,免费开源的通用数据库管理和开发工具,使用非常友好的 ASL 协议.可以通过官方网站或者 Github 进行下载. 由于 DBeaver 基于 Java 开发 ...
- Python的regex模块——更强大的正则表达式引擎
Python自带了正则表达式引擎(内置的re模块),但是不支持一些高级特性,比如下面这几个: 固化分组 Atomic grouping 占有优先量词 Possessive quantifi ...
- 让Docker功能更强大的10个开源工具
让Docker功能更强大的10个开源工具 更好的管理.Web前端程序.更深入地了解容器应用程序,Docker生态系统正在迅速发展,这还得归功于其充满活力的开源社区. 软件项目的成功常常根据其催生的生态 ...
- summerDao-比mybatis更强大无需映射配置的dao工具
summerDao是summer框架中的一个数据库操作工具,项目地址:http://git.oschina.net/xiwa/summer. 怎么比mybatis更强大,怎么比beetlsql更简单, ...
- 【译】AI 让科技公司变得更强大吗
机器学习可能是当今技术中最重要的基本趋势.由于机器学习的基础是数据 - 大量的数据 - 很常见的是,人们越来越担心已经拥有大量数据的公司会变得更强大.这有一定的道理,但是以相当狭窄的方式,同时ML也看 ...
- MyBatis 的真正强大在于它的映射语句 如果有一个独立且完美的数据库映射模式,所有应用程序都可以使用它
mybatis – MyBatis 3 | Mapper XML 文件 http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html mybatis – My ...
- Android内存优化9 内存检测工具3 MAT比Menmery Monitor更强大
在Android性能优化第(一)篇---基本概念中讲了JAVA的四大引用,讲了一下GCRoot,第二篇Memory Monitor检测内存泄露仅仅说了Menmery Monitor的使用,这篇博客谈一 ...
- Android性能优化第(三)篇---MAT比Menmery Monitor更强大
作者 LooperJing 2016.11.17 16:42* 字数 1687 阅读 1603评论 3喜欢 21 在Android性能优化第(一)篇---基本概念中讲了JAVA的四大引用,讲了一下GC ...
- Excel催化剂开源第24波-较VBA更强大的.Net环境的正则表达式
在VBA上可以调用正则表达式库,从而编写正则表达式自定义函数,这个相信不少VBA开发者已经熟知,但VBA的VBScript正则表达式库毕竟是一个过时的产品,不像.Net那样是与时俱进的,所以两者实现出 ...
- 苹果IOS 12将使您的iPhone更安全,并有更强大的黑客保护
一年一度的IOS刷新正在进行中,苹果已经预览了它,beta测试者已经安装了它,当iPhone在9月份到货时我们其他人应该获得iOS12.虽然软件3-D表情符号和屏幕时间限制等功能在软件到货时可能会受到 ...
随机推荐
- UnoCSS原子CSS引擎
UnoCSS是一款原子化的即时按需 CSS 引擎,其中没有核心实用程序,所有功能都是通过预设提供的.默认情况下UnoCSS应用通过预设来实现相关功能. UnoCSS中文文档: https://www. ...
- Nacos源码—8.Nacos升级gRPC分析三
大纲 7.服务端对服务实例进行健康检查 8.服务下线如何注销注册表和客户端等信息 9.事件驱动架构源码分析 7.服务端对服务实例进行健康检查 (1)服务端对服务实例进行健康检查的设计逻辑 (2)服务端 ...
- golang map 和 interface 的一些记录
golang的map读取是不需要判断key是否存在的,不存在的key会返回默认值. 如果map的value是interface,那么interface是需要先进行类型转换的,非要求类型的转换,得到结果 ...
- Seata源码—3.全局事务注解扫描器的初始化
大纲 1.全局事务注解扫描器继承的父类与实现的接口 2.全局事务注解扫描器的核心变量 3.Spring容器初始化后初始化Seata客户端的源码 4.TM全局事务管理器客户端初始化的源码 5.TM组件的 ...
- K8s进阶之外部访问Pod的几种方式
概述 K8s集群内部的Pod默认是不对外提供访问,只能在集群内部进行访问.这样做是为什么呢? 安全性考虑 Kubernetes设计时遵循最小权限原则,即组件仅获得完成其任务所需的最少权限.直接暴露Po ...
- AssemblyResolve巧解未能加载文件或程序集“Newtonsoft.Json, Version=6.0.0.0的问题
问题:未能加载文件或程序集"Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aee ...
- ASP.NET Core Web API中操作方法中的参数来源
在ASP.NET Core Web API中,有多种方式可以传递参数给操作方法.以下是一些常见的参数传递方式: 路由参数(Route Parameters):参数值从URL的路由中提取. // Rou ...
- 使用Files.walk删除文件
摘要:使用Files.walk删除指定文件名的文件. 使用Files.walk工具,递归判断指定目录中的常规文件路径名是否符合约定名称,如果满足条件就删除. public class DelFil ...
- maven pom.xml文件中properties标签介绍
在properties标签内可以把版本号作为变量进行声明,方便maven依赖标签用${变量名}的形式动态获取版本号.这样做的优点是当版本号发生改变时,仅仅需要更新properties标签中的变量值就行 ...
- 【pr】眨眼特效
来源 这个后半段 步骤 新建一段黑场视频 效果->网格化->边角的两个数值调整很大(4000,4000),现在黑场只剩下一个白色十字架. 效果控件->网格->锚点->第一 ...