Introducing mybatis-mate: Enterprise‑Level MyBatis Extension for Sharding, Data Encryption, Auditing, and More
The article presents mybatis-mate, an enterprise‑grade MyBatis module that provides sharding, data auditing, sensitive‑word filtering, field encryption, dictionary write‑back, data permission, automatic DDL maintenance, dynamic multi‑datasource switching, and distributed transaction logging, offering developers a more agile and elegant way to handle data.
0. Introduction
mybatis-mate is an enterprise‑level MyBatis module that supports sharding, data auditing, sensitive word filtering (Aho‑Corasick algorithm), field encryption, dictionary write‑back (data binding), data permission, automatic table‑structure generation and SQL maintenance, aiming to handle data more agilely and elegantly.
1. Main Features
Dictionary binding
Field encryption
Data desensitization
Dynamic table‑structure maintenance
Data audit records
Data scope (data permission)
Database sharding, dynamic datasource, read‑write separation, automatic health‑check switching
2. Usage
2.1 Dependency Import
Spring Boot automatic dependency annotation package
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-mate-starter</artifactId>
<version>1.0.8</version>
</dependency>Annotation (entity sub‑package usage)
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-mate-annotation</artifactId>
<version>1.0.8</version>
</dependency>2.2 Field Data Binding (Dictionary Write‑Back)
Example: map user_sex dictionary to sexText property.
@FieldDict(type = "user_sex", target = "sexText")
private Integer sex;
private String sexText;Implement IDataDict to provide dictionary data source and inject into Spring.
@Component
public class DataDict implements IDataDict {
/** fetch from DB or cache */
private Map<String, String> SEX_MAP = new ConcurrentHashMap<String, String>() {{
put("0", "女");
put("1", "男");
}};
@Override
public String getNameByCode(FieldDict fieldDict, String code) {
System.err.println("字段类型:" + fieldDict.type() + ",编码:" + code);
return SEX_MAP.get(code);
}
}2.3 Field Encryption
Use @FieldEncrypt annotation to encrypt storage and automatically decrypt on query. Global and annotation‑level algorithms can be configured, and custom IEncryptor can be injected.
@FieldEncrypt(algorithm = Algorithm.PBEWithMD5AndDES)
private String password;2.4 Field Desensitization
Use @FieldSensitive annotation to apply predefined or custom masking strategies (9 built‑in types). Example for Chinese name, bank account, phone number, etc.
@FieldSensitive(type = "testStrategy")
private String username;
@FieldSensitive(type = SensitiveType.mobile)
private String mobile;Custom strategy can be added via Spring configuration.
@Configuration
public class SensitiveStrategyConfig {
@Bean
public ISensitiveStrategy sensitiveStrategy() {
// custom testStrategy handling
return new SensitiveStrategy().addStrategy("testStrategy", t -> t + "***test***");
}
}2.5 Automatic DDL Maintenance
Handles table‑structure upgrades and versioned SQL maintenance for MySQL and PostgreSQL.
@Component
public class PostgresDdl implements IDdl {
@Override
public List<String> getSqlFiles() {
return Arrays.asList("db/tag-schema.sql", "D:\\db\\tag-data.sql");
}
}DDL can also be executed dynamically.
ddlScript.run(new StringReader("DELETE FROM user;\nINSERT INTO user (id, username, password, sex, email) VALUES (20, 'Duo', '123456', 0, '[email protected]');"));2.6 Dynamic Multi‑Datasource Master‑Slave Switching
Use @Sharding annotation to switch data sources freely at mapper level.
@Mapper
@Sharding("mysql")
public interface UserMapper extends BaseMapper
{
@Sharding("postgres")
Long selectByUsername(String username);
}Custom sharding strategy can be defined.
@Component
public class MyShardingStrategy extends RandomShardingStrategy {
@Override
public void determineDatasourceKey(String group, Invocation invocation, SqlCommandType sqlCommandType) {
this.changeDatabaseKey(group, sqlCommandType, keys -> chooseKey(keys, invocation));
}
}Configuration example for health check, primary datasource, and node definitions.
mybatis-mate:
sharding:
health: true
primary: mysql
datasource:
mysql:
- key: node1
- key: node2
cluster: slave
postgres:
- key: node12.7 Distributed Transaction Logging
Performance interceptor logs each SQL statement with execution time, optional formatting, and can throw an exception if execution exceeds the configured maxTime.
@Slf4j
@Component
@Intercepts({
@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
@Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
@Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})
})
public class PerformanceInterceptor implements Interceptor {
private long maxTime = 0;
private boolean format = false;
private boolean writeInLog = false;
// ... (intercept, plugin, setProperties, helper methods) ...
}2.8 Data Permission
Add @DataScope on mapper methods to enforce row‑level permissions.
@DataScope(type = "test", value = {
@DataColumn(alias = "u", name = "department_id"),
@DataColumn(alias = "u", name = "mobile")
})
@Select("select u.* from user u")
List
selectTestList(IPage
page, Long id, @Param("name") String username);Provide a IDataScopeProvider bean to build WHERE clauses dynamically.
@Bean
public IDataScopeProvider dataScopeProvider() {
return new AbstractDataScopeProvider() {
@Override
protected void setWhere(PlainSelect plainSelect, Object[] args, DataScopeProperty dataScopeProperty) {
if ("test".equals(dataScopeProperty.getType())) {
for (DataColumnProperty dataColumn : dataScopeProperty.getColumns()) {
if ("department_id".equals(dataColumn.getName())) {
Set<String> deptIds = new HashSet<>();
deptIds.add("1");
deptIds.add("2");
deptIds.add("3");
deptIds.add("5");
ItemsList itemsList = new ExpressionList(deptIds.stream().map(StringValue::new).collect(Collectors.toList()));
InExpression inExpression = new InExpression(new Column(dataColumn.getAliasDotName()), itemsList);
if (plainSelect.getWhere() == null) {
plainSelect.setWhere(new Parenthesis(inExpression));
} else {
plainSelect.setWhere(new AndExpression(plainSelect.getWhere(), inExpression));
}
} else if ("mobile".equals(dataColumn.getName())) {
LikeExpression likeExpression = new LikeExpression();
likeExpression.setLeftExpression(new Column(dataColumn.getAliasDotName()));
likeExpression.setRightExpression(new StringValue("%1533%"));
plainSelect.setWhere(new AndExpression(plainSelect.getWhere(), likeExpression));
}
}
}
}
};
}Resulting SQL example:
SELECT u.* FROM user u
WHERE (u.department_id IN ('1','2','3','5')) AND u.mobile LIKE '%1533%' LIMIT 1,10For more examples, see the paid version repository:
https://gitee.com/baomidou/mybatis-mate-examples
PS: If you find this sharing useful, please like and watch.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.