Backend Development 12 min read

Implementing Environment-Based Data Isolation in MyBatis with Custom Interceptors and Annotations

This article describes a practical approach to achieve environment-based data isolation in a Java application by adding an 'env' field to tables, using a custom MyBatis interceptor to rewrite SQL, and defining annotations with AOP to control environment filtering, while discussing challenges and refactoring considerations.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Implementing Environment-Based Data Isolation in MyBatis with Custom Interceptors and Annotations

Background

In a system where pre‑release, gray and online environments share a single database, an env column was added to each table to distinguish data.

Isolation before

Initially only one core table had the env field; later dozens of tables needed the column, requiring a migration strategy that preserved existing data.

Transformation

New rows are inserted with env='all' to be visible in all environments; queries are rewritten to add env in (${currentEnv},'all') .

Solution

A custom MyBatis interceptor reads the current environment from application.properties and rewrites SQL statements at runtime, avoiding changes to DO, Mapper or XML files.

Key benefits:

Business code remains unchanged.

Reduced manual field addition and error risk.

Easier future extensions.

Implementation details include using JSqlParser to parse and modify SQL, handling INSERT and SELECT cases, and storing the environment value in a thread‑local context.

@Intercepts
(
{
@Signature
(type = Executor
.
class
,
method
= "update", args = {MappedStatement
.
class
,
Object
.
class
})}
)
@
Component
public
class
EnvIsolationInterceptor
implements
Interceptor
{
......
@Override
publicObjectintercept(Invocation invocation) throwsThrowable {
......
if
(SqlCommandType.INSERT == sqlCommandType) {
try
{
// 重写 sql 执行语句,填充环境参数等
insertMethodProcess(invocation, boundSql);
}
catch
(Exception exception) {
log.error("parser insert sql exception, boundSql:" + JSON.toJSONString(boundSql), exception);
throwexception;
}
}
returninvocation.proceed();
}
}

Evolution

Later requirements demanded skipping environment checks for certain tables or methods. An annotation @InvokeChainSkipEnvRule with AOP was introduced to declare skip rules at the method level.

@Target
({ElementType.METHOD})
@Retention
(RetentionPolicy.RUNTIME)
public
@interface
InvokeChainSkipEnvRule {
/**
* 是否跳过环境。默认 true,不推荐设置 false
*
*
@return
*/
boolean isKip() default true;
/**
* 赋值则判断规则,否则不判断
*
*
@return
*/
String[] skipEnvList() default {};
/**
* 赋值则判断规则,否则不判断
*
*
@return
*/
String[] skipTableList() default {};
}

The interceptor reads these rules from the application context to decide whether to apply the environment filter.

Shortcomings

The whole table is skipped, which is a coarse granularity.

Annotations can only be placed on entry methods, not on internal utility methods.

Reflection

The article concludes that a well‑designed technical solution (or separate databases) should be considered from the start to avoid invasive code changes and maintain data safety across environments.

JavaAOPMyBatisData IsolationAnnotationsCustom Interceptor
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.