Northwind Electronics ENTERPRISE
#508

Multi-tenant

One database, many companies. Hibernate adds the tenant filter to every query for you.

Technique: Hibernate @TenantId + CurrentTenantIdentifierResolver + sub-domain / session resolution
Read the code: src/main/java/com/study/advlab/core/TenantFilter.javasrc/main/java/com/study/advlab/core/TenantIdentifierResolver.javasrc/main/java/com/study/advlab/tenancy/TenantService.java
This request
Northwind Electronics
tenant_id = 1 · code northwind
Found by: Signed-in user "nina.admin" (session)
Open a company by its sub-domain (no DNS needed - browsers send *.localhost to this PC):
Proof that the data is isolated
productRepository.count() JPA, @TenantId 41
SELECT COUNT(*) FROM product WHERE tenant_id = ?41
SELECT COUNT(*) FROM product native, no filter 110
productRepository.findById(42) - a product of Siam Sport & Outdoor empty

The repository methods have no tenant parameter. Hibernate adds where tenant_id = ? to every query of an entity with @TenantId, and fills tenant_id on insert.

Native SQL (JdbcTemplate) is not filtered - every hand-written query in this project passes tenant_id = ? itself. Forgetting it is the classic multi-tenant bug.

Companies rows per table - native SQL, like a database admin sees it
CompanyUsersproductcustomerpurchasereviewtxnkb_articleleadface_personexperimentgeo_zonechat_messagePlanStatus
Northwind Electronics
id 1 · northwind
0 0 0 0 0 0 0 0 0 0 0
Siam Sport & Outdoor
id 2 · siamsport
0 0 0 0 0 0 0 0 0 0 0
Blue Harbor Home
id 3 · blueharbor
0 0 0 0 0 0 0 0 0 0 0
Add a company
Three ways to do multi-tenancy
ApproachIsolationCost
Shared tables + tenant_id (this lab)by code - filter every querycheapest, easiest to run
Schema per tenantby database schemamedium, migrations × N
Database per tenantstrongest, own backupsmost expensive

SQL Server can add a safety net with Row-Level Security (a security policy on tenant_id), so even a forgotten WHERE cannot leak.