MyBatis插件实现数据脱敏的核心是拦截ParameterHandler(参数加密)和ResultSetHandler(结果解密),配合@SensitiveData和@EncryptTransaction注解标记字段,通过可替换的IEncryptor接口封装算法,支持嵌套对象、Map参数及配置化密钥。

用 MyBatis 插件实现数据脱敏或字段加解密,核心是拦截 SQL 执行前的参数设置和执行后的结果处理,配合自定义注解标记敏感字段,做到业务无感知、配置灵活、可扩展性强。
关键拦截点选对才有效
MyBatis 提供四大可拦截接口,脱敏场景主要用两个:
- ParameterHandler:在 SQL 执行前拦截,对写入参数中的敏感字段(如手机号、身份证号)做加密,再传给数据库
- ResultSetHandler:在查询返回后拦截,对查出的密文字段做解密,还原为明文对象供上层使用
不建议拦截 Executor 或 StatementHandler——前者粒度太粗(影响所有 SQL),后者需手动解析 SQL,易出错且难维护。
注解驱动,标记即生效
通过两个轻量注解控制作用范围:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- @SensitiveData:加在实体类上,表示该类整体参与脱敏流程
- @EncryptTransaction(或 @EncryptedField):加在具体字段或 Mapper 方法参数上,指定哪些字段需要加解密
插件运行时扫描对象结构,只对带注解的字段触发加解密逻辑,避免误操作正常字段。比如:
public class User {private Long id;
@EncryptTransaction
private String phone;
@EncryptTransaction
private String idCard;
}
加解密逻辑要收口、可替换
不要把 AES/SM4 等算法硬编码进插件。推荐做法:
- 定义统一接口 IDecryptUtil 或 IEncryptor,声明 encrypt() / decrypt() 方法
- 提供默认实现(如基于 AES 的 BasicTextEncryptor),也支持按字段指定不同实现(例如邮箱用 Base64,密码用 SM4)
- 密钥可通过配置项注入(如
mybatis-crypto.default-key),避免写死
这样后续更换算法、调整密钥策略,只需改配置或换实现类,无需动插件主逻辑。
注意几个实际落地细节
真实项目中容易踩坑的地方:
- 嵌套对象(如 User 中有 Address 对象)需递归扫描字段,否则子对象里的 @EncryptTransaction 不生效
- Map 类型参数(如
@Param("params") Map<String, Object>)需提取 key 对应的 value 再判断是否需加密 - 历史数据迁移需单独开发脚本,插件只管新增/修改/查询,不自动处理存量明文
- 开启 debug 日志观察
ParameterHandler.setParameters和ResultSetHandler.handleResultSets是否被正确拦截
不复杂但容易忽略

















