Skip to content

Multi-Tenant Plugin

TenantLineInnerInterceptor is a plugin provided by MyBatis-Plus for implementing multi-tenant data isolation. This plugin ensures that each tenant can only access their own data, thereby achieving secure data isolation.

Example Project

To better understand how to use TenantLineInnerInterceptor, you can refer to the official example project: 👉 mybatis-plus-sample-tenant

Property Introduction

The key property of TenantLineInnerInterceptor is tenantLineHandler, which is an instance of the TenantLineHandler interface used to handle tenant-related logic.

Property NameTypeDefault ValueDescription
tenantLineHandlerTenantLineHandlerTenant Handler (TenantId Row Level)

The TenantLineHandler interface defines the following methods:

public interface TenantLineHandler {
/**
* Get the tenant ID value expression. Only supports a single ID value.
*
* @return Tenant ID value expression
*/
Expression getTenantId();
/**
* Get the tenant field name.
* Default field name is: tenant_id
*
* @return Tenant field name
*/
default String getTenantIdColumn() {
return "tenant_id";
}
/**
* Determine whether to ignore adding the multi-tenant condition based on the table name.
* By default, all tables are parsed and the multi-tenant condition is added.
*
* @param tableName Table name
* @return Whether to ignore. true: ignore, false: need to parse and add multi-tenant condition
*/
default boolean ignoreTable(String tableName) {
return false;
}
/**
* Ignore the logic for inserting the tenant field.
*
* @param columns Insert fields
* @param tenantIdColumn Tenant ID field
* @return
*/
default boolean ignoreInsert(List<Column> columns, String tenantIdColumn) {
return columns.stream().map(Column::getColumnName).anyMatch(i -> i.equalsIgnoreCase(tenantIdColumn));
}
}

Usage

Step 1: Implement the Tenant Handler

Implement the TenantLineHandler interface to create a tenant handler. In this example, we assume each tenant has a unique tenantId, and we obtain the current tenant’s tenantId from the request header.

@Component
public class CustomTenantHandler implements TenantLineHandler {
@Override
public Expression getTenantId() {
// Assume there is a tenant context from which the current user's tenant can be obtained
Long tenantId = TenantContextHolder.getCurrentTenantId();
// Return the tenant ID expression. LongValue is the class representing the bigint type in JSQLParser
return new LongValue(tenantId);;
}
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
@Override
public boolean ignoreTable(String tableName) {
// Return whether to ignore this table based on your needs
return false;
}
}

Step 2: Inject the Tenant Handler into the Plugin

Inject your custom tenant handler into the TenantLineInnerInterceptor:

@Configuration
@MapperScan("com.yourpackage.mapper")
public class MybatisPlusConfig {
@Autowired
private CustomTenantHandler customTenantHandler;
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
TenantLineInnerInterceptor tenantInterceptor = new TenantLineInnerInterceptor();
tenantInterceptor.setTenantLineHandler(customTenantHandler);
interceptor.addInnerInterceptor(tenantInterceptor);
return interceptor;
}
}

By following the steps above, you have successfully configured the multi-tenant plugin in your Spring Boot project and implemented a simple tenant handler. Your application will now automatically handle multi-tenant data isolation based on the current request’s tenant ID.

Please note that in practice, the method for obtaining the tenant ID may vary depending on your application architecture and business requirements. Additionally, ensure security considerations are taken into account when handling tenant IDs to avoid potential security risks.

Local SQL Parsing Cache

To improve performance, MyBatis-Plus supports local caching of SQL parsing. You can set the cache handling class as follows:

static {
// Default supports serialization FstSerialCaffeineJsqlParseCache, JdkSerialCaffeineJsqlParseCache
JsqlParserGlobal.setJsqlParseCache(new JdkSerialCaffeineJsqlParseCache(
(cache) -> cache.maximumSize(1024)
.expireAfterWrite(5, TimeUnit.SECONDS))
);
}

Automatically Adding Tenant Field on Insert

By default, insert SQL requires tenant condition checking. Therefore, it needs to be used in conjunction with the Automatic Field Population feature to populate the tenant field; otherwise, the tenant field will not be automatically saved to the database.

Notes

Through the above configuration and usage methods, you can implement multi-tenant data isolation in your MyBatis-Plus application, ensuring data security for each tenant.

Baomidou

© 2016-2025 Baomidou™. All Rights Reserved.

Power by Astro Starlight | Sponsored by JetBrains

渝ICP备2021000141号-1 | 渝公网安备50011302222097