Backend Development 9 min read

Implementing Data Isolation with MyBatis Interceptor and Custom Annotations

The article describes how to enforce environment‑based data isolation in a shared database by adding an env column, using a MyBatis interceptor to inject and filter this field at runtime, and employing a custom @InvokeChainSkipEnvRule annotation with AOP to selectively bypass the rule, keeping existing code untouched.

Java Tech Enthusiast
Java Tech Enthusiast
Java Tech Enthusiast
Implementing Data Isolation with MyBatis Interceptor and Custom Annotations

Background

In a multi‑environment deployment (pre‑release, gray, online) a single database is shared. Each table originally lacked an env column, causing data from different environments to mix.

Data Isolation Strategy

All tables were retrofitted with an env field. Historical data were marked with env='all' to keep compatibility. Queries now need to filter by the current environment.

SELECT XXX FROM tableName WHERE env = ${environment} AND ${condition}

MyBatis Interceptor Solution

A custom MyBatis interceptor rewrites SQL at runtime: it injects the environment value on INSERT and adds an env IN (${environment},'all') condition on SELECT. This avoids touching DO, Mapper or XML files.

SELECT xxx FROM ${tableName} WHERE env IN (${currentEnv},'all') AND ${otherCondition}

The interceptor reads the environment from application.properties and uses JSqlParser to modify the statements.

Custom Annotation & AOP

To make the rule reusable, a custom annotation @InvokeChainSkipEnvRule is defined. Methods annotated with it specify which environments or tables should skip the check.

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface InvokeChainSkipEnvRule {
    boolean isKip() default true;
    String[] skipEnvList() default {};
    String[] skipTableList() default {};
}

An AOP aspect reads the annotation and stores the rule in a thread‑local context, which the interceptor then consults.

Usage Example

@SneakyThrows
@GetMapping("/importSignedUserData")
@InvokeChainSkipEnvRule(skipEnvList = {"pre"}, skipTableList = {"project"})
public void importSignedUserData(HttpServletRequest request, HttpServletResponse response) {
    // business logic
}

Refactoring Considerations

Minimize changes to existing code.

Separate business logic from infrastructure concerns.

Prefer a single point of modification (interceptor) for maintainability.

Conclusion

The approach demonstrates how a MyBatis interceptor combined with custom annotations can achieve fine‑grained data isolation and selective sharing across environments while keeping the codebase clean and extensible.

JavaAOPMyBatisCustom AnnotationData IsolationInterceptor
Java Tech Enthusiast
Written by

Java Tech Enthusiast

Sharing computer programming language knowledge, focusing on Java fundamentals, data structures, related tools, Spring Cloud, IntelliJ IDEA... Book giveaways, red‑packet rewards and other perks await!

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.