Core Positioning

SaaS Multi-Tenancy allows you to serve multiple enterprise clients with a single codebase, where each client (tenant) can only see their own data, completely isolated from each other. Whether building a vertical SaaS product or managing multiple subsidiaries within an enterprise, this is an indispensable capability.

Two approaches: Column-based isolation (lightweight, suitable for small-to-medium scale) and database isolation (physical isolation, suitable for large-scale SaaS).


Suitable Users

ScenarioRecommended ApproachReason
SaaS Startup PhaseColumn-based isolationSimple operations, one database handles everything
Large SaaS PlatformDatabase isolationPhysical isolation, high security, independent backups
Enterprise Multi-CompanyColumn-based isolationLimited number of companies, logical isolation is sufficient
Finance/Healthcare ComplianceDatabase isolationData must be physically isolated

Two Approaches Comparison

graph TB subgraph COLUMN["Approach 1: Column-Based Isolation (COLUMN Mode)"] direction TB C1["All tenants share
same database, same tables"] C2["Each table adds
tenant_id column"] C3["SQL Interceptor
auto-appends WHERE tenant_id = ?"] C4["Pros: Simple operations, high resource utilization
Cons: Logical isolation, moderate security"] C1 --> C2 --> C3 --> C4 end subgraph DATASOURCE["Approach 2: Database Isolation (DATASOURCE Mode)"] direction TB D1["Master DB: Shared tables
Users/Menus/Config/Tenant info"] D2["Tenant DB A: Business tables"] D3["Tenant DB B: Business tables"] D4["Tenant DB C: Business tables"] D5["Pros: Physical isolation, high security, independent backups
Cons: Complex operations, lower resource utilization"] D1 --> D2 D1 --> D3 D1 --> D4 D2 & D3 & D4 --> D5 end

Detailed Comparison

DimensionColumn-Based (COLUMN)Database Isolation (DATASOURCE)
Isolation LevelLogical isolationPhysical isolation
SecurityMedium (relies on SQL interceptor)High (database-level isolation)
Resource UtilizationHigh (shared connection pool)Low (independent connections per tenant)
Operations ComplexityLow (single DB operations)High (multi-DB operations)
ScalabilityLimited by single DB performanceHorizontally scalable
Data BackupNeed to filter by tenant_idIndependent backup per tenant
Applicable ScaleHundreds of tenantsThousands/Tens of thousands of tenants
Technical ImplementationMyBatis Plus interceptordynamic-datasource

Column-Based Isolation Implementation

sequenceDiagram participant U as User (Tenant A) participant APP as Application Layer participant INTERCEPTOR as SQL Interceptor participant DB as Shared Database U->>APP: Query customer list APP->>INTERCEPTOR: SELECT * FROM crm_customer INTERCEPTOR->>INTERCEPTOR: Auto-append tenant_id = 'A' INTERCEPTOR->>DB: SELECT * FROM crm_customer
WHERE tenant_id = 'A' DB-->>APP: Returns only Tenant A's data APP-->>U: Display customer list

Core Mechanism: Through MyBatis Plus’s multi-tenant plugin, automatically adds tenant_id condition before executing any SQL, completely transparent to business code.


Database Isolation Implementation

Based on dynamic-datasource dynamic data sources, when a request comes in, it switches to the corresponding data source based on the current tenant ID:

spring:
  datasource:
    dynamic:
      primary: master  # Master DB (shared tables)
      datasource:
        master:        # Master DB config
          url: jdbc:mysql://localhost:3306/ruoyi_master
        tenant_1:      # Tenant 1's independent database
          url: jdbc:mysql://localhost:3306/ruoyi_tenant_1
        tenant_2:      # Tenant 2's independent database
          url: jdbc:mysql://localhost:3306/ruoyi_tenant_2

Tenant Package Management

graph LR PACKAGE1["Basic Package
System Management + Basic Features"] PACKAGE2["Professional Package
Basic + CRM + ERP"] PACKAGE3["Enterprise Package
All Features"] TenantA["Tenant A"] --> PACKAGE1 TenantB["Tenant B"] --> PACKAGE2 TenantC["Tenant C"] --> PACKAGE3

Each tenant can be bound to a package, which defines the menus and features visible to that tenant. Supports automatic disabling upon package expiration.

docs