Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_017ic4b4VQVEJWetTT1dYzyJ
44 lines
2.6 KiB
Plaintext
44 lines
2.6 KiB
Plaintext
# @TenantId on PostgreSQL (PostgreSQL 17.11), Hibernate 7.4.14.Final
|
|
|
|
== DDL Hibernate generated (read back from the catalog)
|
|
column amount numeric nullable=YES
|
|
column id bigint nullable=NO
|
|
column number character varying nullable=YES
|
|
column tenant_id character varying nullable=NO
|
|
unique UNIQUE (tenant_id, number)
|
|
|
|
== insert: nobody sets tenant_id in Java
|
|
-- as acme: save(INV-1)
|
|
sql> insert into invoice (amount,number,tenant_id) values (?,?,?)
|
|
entity.tenantId after save = acme
|
|
-- as globex: save(INV-1) - same invoice number, allowed by UNIQUE(tenant_id, number)
|
|
sql> insert into invoice (amount,number,tenant_id) values (?,?,?)
|
|
ids: acme INV-1=1, globex INV-1=2 (one IDENTITY column shared by all tenants)
|
|
|
|
== reads are filtered
|
|
-- as acme: findAll()
|
|
sql> select i1_0.id,i1_0.amount,i1_0.number,i1_0.tenant_id from invoice i1_0 where i1_0.tenant_id = ?
|
|
rows = 2, numbers = [INV-1, INV-2]
|
|
-- as globex: findById(acme's id 1)
|
|
sql> select i1_0.id,i1_0.amount,i1_0.number,i1_0.tenant_id from invoice i1_0 where i1_0.id=? and i1_0.tenant_id = ?
|
|
result = Optional.empty
|
|
|
|
== bulk HQL is scoped too
|
|
-- as acme: update Invoice set amount = 0
|
|
sql> update invoice i1_0 set amount=0 where i1_0.tenant_id = ?
|
|
rows updated = 2 (globex's row untouched)
|
|
|
|
== what @TenantId does NOT cover: native SQL
|
|
-- as acme: native query select count(*) from invoice
|
|
result = 3 (acme owns 2 rows; the native query saw every tenant)
|
|
|
|
== no tenant set
|
|
-- strict resolver (throws when TenantContext is empty): repo.findAll() with no tenant
|
|
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction <- caused by com.ankurm.multitenancy.tenant.MissingTenantException: no tenant in TenantContext: refusing to open a tenant-scoped session
|
|
-- lenient resolver (returns null): repo.findAll() with no tenant
|
|
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction <- caused by org.hibernate.HibernateException: SessionFactory configured for multi-tenancy, but no tenant identifier specified
|
|
|
|
== writing a row for a different tenant than the session's
|
|
-- as acme: new Invoice with tenantId manually set to globex, saveAndFlush
|
|
org.springframework.dao.DataIntegrityViolationException: assigned tenant id differs from current tenant id [globex != acme] for entity com.ankurm.multitenancy.discriminator.Invoice.tenantId <- caused by org.hibernate.PropertyValueException: assigned tenant id differs from current tenant id [globex != acme] for entity com.ankurm.multitenancy.discriminator.Invoice.tenantId
|