Class TenantContextIdentifierResolver
- All Implemented Interfaces:
org.hibernate.context.spi.CurrentTenantIdentifierResolver<String>
把 TenantContext 接到 Hibernate 原生 discriminator 多租戶的 resolver
供 TenantId 使用:Hibernate 於每個 Session 建構時呼叫
resolveCurrentTenantIdentifier(),據以決定該 Session 的租戶分區。
為何是「類別 + 設定」而非 Spring `@Bean`
Hibernate 的 hibernate.tenant_identifier_resolver 接受類名字串並自行實例化,故本類別
刻意保持無依賴、可無參建構(TenantContext 全靜態)。這是必要的——一旦任何實體掛
@TenantId,_tenantId filter 即在 SessionFactory 層定義,於是每一個 Session 建構都會走
AbstractSharedSessionContract 的 setUpMultitenancy,取不到租戶識別
就丟 HibernateException: SessionFactory configured for multi-tenancy, but no tenant identifier specified。若 resolver 只是應用層 @Configuration 裡的 @Bean,不載入該 config 的
@DataJpaTest slice 會整個 context 起不來(實測)。改由設定注入即無此問題,且不需
autoconfiguration(見 ADR-014:框架刻意不採 autoconfiguration)。
ROOT_TENANT:無租戶 context 的表達
Hibernate 不接受 resolver 回 null(見上述 setUpMultitenancy),故「無租戶」以
ROOT_TENANT 哨兵表達,並由 isRoot(String) 宣告它可存取所有分區——Hibernate 據此跳過
租戶 filter:
// AbstractSharedSessionContract#setUpMultitenancy
if ( resolver == null || !resolver.isRoot( tenantIdentifier ) ) {
// turn on the filter, unless this is the "root" tenant with access to all partitions
loadQueryInfluencers.enableFilter( TenantIdBinder.FILTER_NAME )...
}
兩類到達 root 的執行緒,皆為刻意:
- 系統管理員:其帳號不屬於任何租戶(租戶 ID 為 null)→ 解析鏈回 null → root → 跨租戶視野
- 背景執行緒(排程 /
@Async):天生無 context → root → 得以跨租戶撈取
root 亦可於寫入時顯式指定租戶(TenantIdGeneration:「the root tenant is allowed to set
the tenant id explicitly」),故 seed/管理工具可跨租戶建資料。
root 的讀寫權界(決策)
- 跨租戶讀取:允許(本機制的目的)。
- 修改他人租戶的既有資料:允許——經決策接受,對齊 Hibernate 自身模型
(
CurrentTenantIdentifierResolver.isRoot(T)的定義即「a root tenant with access to all partitions」)。租戶歸屬不受影響:@TenantId欄位為updatable = false。舊機制在此情境 會拋IllegalStateException,此為刻意放寬。 - 建立租戶業務資料:須指明租戶——以
TenantContext.runAs(String, Runnable)或顯式setTenantId(...)(後者為 Hibernate 支援的 root 路徑)。兩者皆無時,注入的會是ROOT_TENANT哨兵、該列 對所有租戶皆不可見(靜默污染),故TenantAwareEntity的@PrePersist守衛擋下。
三者一致:讀放行、改不動歸屬故放行、建立只擋「租戶無處可得」這一種必然污染的情況。
- See Also:
-
Field Summary
Fields -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionbooleanboolean
-
Field Details
-
ROOT_TENANT
-
-
Constructor Details
-
TenantContextIdentifierResolver
public TenantContextIdentifierResolver()
-
-
Method Details
-
resolveCurrentTenantIdentifier
-
validateExistingCurrentSessions
public boolean validateExistingCurrentSessions()- Specified by:
validateExistingCurrentSessionsin interfaceorg.hibernate.context.spi.CurrentTenantIdentifierResolver<String>
-
isRoot
-