Multi-Tenant Support in the Mall E-Commerce Platform: Architecture and Implementation Options
The Mall e-commerce platform implements a single-tenant architecture that requires separate deployments for each tenant, with no built-in tenant isolation in the database schema or application code.
The macrozheng/mall repository is a widely-used open-source e-commerce system built with Spring Boot and MyBatis. While it delivers comprehensive B2C functionality, its approach to multi-tenant support follows an instance-per-tenant model rather than embedding tenant discrimination within the codebase.
Current Architecture: Single-Tenant Design
The Mall codebase is explicitly designed as a single-tenant application. A comprehensive review of the repository reveals no Tenant entities, tenantId fields, or storeId columns anywhere in the model or service layers.
Database Schema Structure
In document/sql/mall.sql, the entire database schema is defined without tenant isolation. Tables such as pms_product, oms_order, and ums_admin contain no tenant identifier columns. This design necessitates that each tenant operates with a dedicated database instance to ensure complete data isolation.
Service Layer Implementation
Core business services in mall-admin/src/main/java/com/macro/mall/ operate on entities without tenant scoping. Classes like OmsOrderService and PmsProductService process requests without distinguishing between different tenants, handling all data as if belonging to a single organization.
Security Configuration
The mall-security module configures Spring Security globally without tenant-aware authentication. Located in mall-security/src/main/java/com/macro/mall/security/, this configuration authenticates users against a single user store without implementing tenant-specific permission models or isolated security contexts.
Instance-Per-Tenant Deployment Strategy
Given the absence of embedded multi-tenant logic, Mall's approach to serving multiple tenants relies on infrastructure isolation rather than application-level discrimination.
Separate Deployment Instances
To support multiple tenants, operators must spin up separate deployments of the entire application stack. Each instance requires:
- An independent database (or schema copy) populated from
document/sql/mall.sql - Dedicated configuration files (
application.yml) with unique datasources and server ports - Isolated caching layers and file storage systems
Configuration Management
The application.yml files contain global settings without per-tenant sections. Deployment-time configurations must be duplicated and customized for each tenant instance, managing separate connection pools, Redis databases, and storage endpoints for every deployment.
Implementing True Multi-Tenant Support
To achieve shared-infrastructure multi-tenancy within a single deployment, significant modifications to the data model, persistence layer, and security context are required.
Database Schema Modifications
Add a tenant_id column to every table storing tenant-specific data. This includes core tables like pms_product, oms_order, and ums_member, establishing a foreign key relationship to a central tenant registry.
MyBatis Model Extensions
Extend entity classes in the domain model to include tenant identification:
public class PmsProduct {
private Long id;
private String name;
// ... existing fields ...
private Long tenantId; // New field for tenant isolation
// Getter and setter
public Long getTenantId() { return tenantId; }
public void setTenantId(Long tenantId) { this.tenantId = tenantId; }
}
Apply similar modifications to OmsOrder, PmsBrand, and other domain entities in the mall-mbg module.
Tenant-Aware SQL Interception
Implement a MyBatis interceptor to automatically append tenant filtering to database operations:
@Component
public class TenantInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
Object parameter = invocation.getArgs()[1];
BoundSql boundSql = ms.getBoundSql(parameter);
String sql = boundSql.getSql();
// Retrieve current tenant from ThreadLocal context
Long tenantId = TenantContextHolder.getTenantId();
if (tenantId != null && sql.trim().toUpperCase().startsWith("SELECT")) {
// Append tenant filtering - production code should use proper SQL parsing
sql = sql.replaceFirst("(?i)FROM",
"FROM (SELECT * FROM (" + sql + ") t WHERE t.tenant_id = " + tenantId + ") sub FROM");
}
// SQL replacement logic requires reflection or custom SqlSource implementation
// ... implementation details ...
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {}
}
Alternatively, integrate MyBatis-Plus's built-in tenant plugin for more robust SQL manipulation without manual string replacement.
Authentication and Context Management
Modify the authentication flow to establish tenant context after login. Store the current tenant identifier in a ThreadLocal variable or Spring SecurityContext within a TenantContextHolder class, making it available to the MyBatis interceptor for all subsequent database operations.
Update service methods to automatically set the tenant ID when creating new entities, ensuring data integrity across the application layer.
Summary
- The Mall platform is single-tenant by design, with no embedded multi-tenant support in the current codebase according to the source analysis.
- Database tables lack tenant identifiers - the schema in
document/sql/mall.sqlcontains notenant_idcolumns. - Services operate without tenant scoping -
OmsOrderServiceandPmsProductServiceprocess all data as belonging to a single organization. - Current multi-tenant strategy requires separate deployments - each tenant needs isolated application instances with dedicated databases and configurations.
- True multi-tenancy requires custom development - including schema modifications, MyBatis interceptors, and tenant-aware authentication contexts.
Frequently Asked Questions
Does Mall support multi-tenant architecture out of the box?
No, the macrozheng/mall repository is explicitly designed as a single-tenant system. The codebase contains no tenant isolation logic, with all services in mall-admin operating on a unified data model without tenant discrimination.
How can I deploy Mall for multiple clients?
Deploy separate instances of the application for each client, each with its own database initialized from document/sql/mall.sql. Configure independent application.yml files with unique datasources, ports, and storage configurations to ensure complete data isolation between tenants.
What changes are needed to add tenant isolation to Mall?
You must add tenant_id columns to all tenant-specific tables, extend MyBatis entity classes like PmsProduct with tenant fields, implement a MyBatis interceptor to automatically filter SQL by tenant, and modify the security layer to maintain tenant context in a ThreadLocal holder during request processing.
Is there a MyBatis plugin available for tenant filtering?
Yes, MyBatis-Plus provides a built-in tenant plugin that can automatically append WHERE tenant_id = ? conditions to queries. However, Mall uses standard MyBatis, so you would need to either migrate to MyBatis-Plus or implement a custom Interceptor as shown in the code example above to achieve automatic tenant filtering.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →