Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_017ic4b4VQVEJWetTT1dYzyJ
48 lines
2.5 KiB
Markdown
48 lines
2.5 KiB
Markdown
# multitenancy
|
|
|
|
Companion module for the ankurm.com article **Multi-Tenancy with Hibernate 7 and Spring Boot 4: `@TenantId` vs Schema-per-Tenant**
|
|
(https://ankurm.com/hibernate-multi-tenancy-spring-boot-tenantid-vs-schema/).
|
|
Every claim in the article comes from a test here; each test writes what it observed to `output/`. All tests run against a real
|
|
PostgreSQL 17 container started by Testcontainers (needs a Docker daemon).
|
|
|
|
## Versions
|
|
|
|
| Component | Version | Notes |
|
|
|---|---|---|
|
|
| Hibernate ORM | `7.4.14.Final` | newest 7.x GA on Maven Central on 2026-10-29; overrides the `7.4.13.Final` Spring Boot 4.1.2 manages |
|
|
| Spring Boot | `4.1.2` | parent POM |
|
|
| Spring Security (JOSE only) | `7.1.2` | `spring-security-oauth2-jose`, Nimbus JWT; no security filter chain |
|
|
| PostgreSQL / driver | `17.11` / `42.7.14` | `postgres:17-alpine`; Testcontainers `2.0.5` |
|
|
| Java | `25` (Temurin 25.0.5+8) | |
|
|
|
|
## Run
|
|
|
|
```bash
|
|
./scripts/run-all.sh # javap dump + mvn clean test; regenerates everything in output/
|
|
```
|
|
|
|
## Layout
|
|
|
|
| Package | What |
|
|
|---|---|
|
|
| `tenant` | `TenantContext` (ThreadLocal), `JwtTenantFilter`, `TenantIdResolver` (Hibernate resolver), `TenantHibernateConfig`, `TenantNames` allow-list |
|
|
| `discriminator` | `DiscriminatorApp`, `Invoice` with `@TenantId`, repository, controller |
|
|
| `schema` | `SchemaApp`, `Invoice` (no tenant column), `SearchPathConnectionProvider` (shared pool; also the deliberately leaky variant), `PoolPerTenantConnectionProvider`, `SchemaProvisioner` |
|
|
|
|
## Output
|
|
|
|
| File | What it shows |
|
|
|---|---|
|
|
| `00-javap.txt` | `javap` of the tenancy types in the shipped jars; Boot's `HibernatePropertiesCustomizer` package |
|
|
| `01-api-shape.txt` | packages, generics and setting names by reflection |
|
|
| `02-discriminator.txt` | `@TenantId` DDL and SQL, cross-tenant `findById`, bulk HQL, native-SQL bypass, no-tenant and mismatched-tenant failures |
|
|
| `03-schema-per-tenant.txt` | schema-per-tenant on one shared pool: SQL, overlapping ids, ghost tenant, hostile name, pool connection count |
|
|
| `04-search-path-leak.txt` | a provider that forgets to reset `search_path` vs the correct one |
|
|
| `05-pool-per-tenant.txt` | one Hikari pool per tenant: connections per pool in `pg_stat_activity` |
|
|
| `06-http-discriminator.txt` / `07-http-schema.txt` | JWT to tenant over real HTTP: 401 / 403 / 404 / 200 cases |
|
|
|
|
## Not covered (not run)
|
|
|
|
Row-level security, database-per-tenant (separate servers), L2 cache with multi-tenancy, Envers, Flyway per schema, JWKS/asymmetric
|
|
keys, `@Async` / virtual-thread propagation of the tenant, and any load or latency measurement.
|