在多租戶(SaaS)或多分支機構系統中,常見需求:同一套代碼、同一張表結構,按租戶/區域隔離在不同 Schema(Oracle 用戶/PostgreSQL Schema/MySQL Database)中。Hibernate 映射文件若寫死 schema="P_BEIJING" 則無法動態切換。本文介紹通過移除映射文件 schema 屬性、配合 hibernate.default_schema 動態重建 SessionFactory 實現運行時切換的方案,並分析其對全局用戶的影響及多租戶改進路徑。
<!-- 映射文件寫死 schema,無法動態切換 -->
<class name="com.csc.poimanager.dao.Poi" table="POI" schema="P_BEIJING">
業務需求:用戶登錄後,根據其所屬區域(北京/上海/深圳)操作對應 Schema 下的 POI 表。
<class name="com.csc.poimanager.dao.Poi" table="POI"> <!-- 無 schema -->
<property name="hibernate.default_schema">POI_BEIJING</property>
public class HibernateSessionFactory {
private static Configuration configuration;
private static SessionFactory sessionFactory;
static {
configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
}
/**
* 運行時切換 Schema:修改配置屬性並重建 SessionFactory
* @param newSchema 目標 Schema 名稱
*/
public static synchronized void rebuildSessionFactoryForChangeSchema(String newSchema) {
try {
Properties props = configuration.getProperties();
props.put("hibernate.default_schema", newSchema);
// 關鍵:重建 SessionFactory,舊實例將被 GC 回收
sessionFactory = configuration.buildSessionFactory();
log.info("Schema 切換成功: {}", newSchema);
} catch (Exception e) {
log.error("Schema 切換失敗", e);
throw new IllegalStateException("Schema 切換異常", e);
}
}
public static SessionFactory getSessionFactory() { return sessionFactory; }
}
public class SchemaAction {
public void switchToShanghai() {
HibernateSessionFactory.rebuildSessionFactoryForChangeSchema("POI_SHANGHAI");
PoiDAO dao = new PoiDAO();
Transaction tx = dao.getSession().beginTransaction();
dao.save(new Poi("動態切換測試"));
tx.commit();
}
}
| 風險點 | 影響 | 緩解措施 |
|---|---|---|
| 全局生效 | 所有線程/用戶共用同一 SessionFactory,切換影響整個應用 | 僅適用於單租戶應用或維護窗口切換 |
| 重建開銷大 | 重新解析映射、重建連接池、二級緩存失效 | 避免高頻切換;預熱緩存 |
| 舊 Session 失效 | 切換前打開的 Session 仍綁定舊 Schema,操作會報錯 | 切換前關閉所有 Session;或使用 ThreadLocal 綁定新 Session |
| 並發安全 | 多線程並發調用 rebuild 會互相覆蓋 | 方法加 synchronized;生產環境建議單線程維護窗口執行 |
上述方案本質是「串行切換」,不支持多用戶並發訪問不同 Schema。真正的多租戶應採用:
SessionFactory,存入 MapMultiTenantConnectionProvider + CurrentTenantIdentifierResolvertenant_id 列區分數據tenant_id 過濾條件動態重建 SessionFactory 切換 Schema 是快速滿足單租戶/維護場景的權宜之計,嚴禁用於多用戶並發業務。多租戶系統請採用方案 A/B/C,根據隔離要求、租戶數量、運維能力選型。Hibernate 官方多租戶支持(方案 B)是長期演進的標準路徑。