接続ポーリングに影響を与える3つの異なる戦略から選択できます。いずれの場合も、MultiTenantConnectionProvider
の実装を提供する必要があります 。もちろん、選択した戦略は実装に影響を与えます。
MultiTenantConnectionProvider.getAnyConnection()
に関する一般的な注意
getAnyConnection()
メタデータを収集してSessionFactoryをセットアップするためにHibernateが必要とします。通常、マルチテナントアーキテクチャでは、どのテナントも使用しない特別な/マスターデータベース(またはスキーマ)があります。これは一種のテンプレートデータベース(またはスキーマ)です。このメソッドがこのデータベース(またはスキーマ)への接続を返す場合は問題ありません。
戦略1:各テナントには独自のデータベースがあります。 (したがって、それは独自の接続プールです)
この場合、各テナントにはC3POによって管理される独自の接続プールがあり、MultiTenantConnectionProvider
の実装を提供できます。 AbstractMultiTenantConnectionProvider
に基づく
すべてのテナントには独自のC3P0ConnectionProvider
があります 、したがって、selectConnectionProvider(tenantIdentifier)
で行う必要があるのはすべてです 正しいものを返すことです。マップを保持してそれらをキャッシュすることができ、C3POConnectionProviderを次のようなもので遅延初期化することができます:
private ConnectionProvider lazyInit(String tenantIdentifier){
C3P0ConnectionProvider connectionProvider = new C3P0ConnectionProvider();
connectionProvider.configure(getC3POProperties(tenantIdentifier));
return connectionProvider;
}
private Map getC3POProperties(String tenantIdentifier){
// here you have to get the default hibernate and c3po config properties
// from a file or from Spring application context (there are good chances
// that those default properties point to the special/master database)
// and alter them so that the datasource point to the tenant database
// i.e. : change the property hibernate.connection.url
// (and any other tenant specific property in your architecture like :
// hibernate.connection.username=tenantIdentifier
// hibernate.connection.password=...
// ...)
}
戦略2:各テナントには独自のスキーマがあり、単一のデータベースに独自の接続プールがあります
このケースは、ConnectionProvider
に関する最初の戦略と非常によく似ています。 AbstractMultiTenantConnectionProvider
も使用できるため実装 MultiTenantConnectionProvider
を実装するための基本クラスとして
実装は、c3po構成のデータベースの代わりにスキーマを変更する必要があることを除いて、戦略1の推奨実装と非常に似ています
戦略3:各テナントは単一のデータベースに独自のスキーマを持っていますが、共有接続プールを使用しています
すべてのテナントが同じ接続プロバイダーを使用するため、このケースは少し異なります(したがって、接続プールは共有されます)。場合:接続プロバイダーは、接続を使用する前に、使用するスキーマを設定する必要があります。つまり、MultiTenantConnectionProvider.getConnection(String tenantIdentifier)
を実装する必要があります (つまり、AbstractMultiTenantConnectionProvider
によって提供されるデフォルトの実装 動作しません)。
postgresqlを使用すると、次のように実行できます:
SET search_path to <schema_name_for_tenant>;
またはエイリアスを使用する
SET schema <schema_name_for_tenant>;
これがgetConnection(tenant_identifier);
です。 次のようになります:
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
final Connection connection = getAnyConnection();
try {
connection.createStatement().execute( "SET search_path TO " + tenanantIdentifier );
}
catch ( SQLException e ) {
throw new HibernateException(
"Could not alter JDBC connection to specified schema [" +
tenantIdentifier + "]",
e
);
}
return connection;
}
役立つリファレンスはこちら(公式ドキュメント)
その他の便利なリンクC3POConnectionProvider.java
実装で戦略1と戦略2を組み合わせることができます。現在のテナントの正しい接続プロパティ/接続URLを見つける方法が必要です。
編集
戦略2と戦略3のどちらを選択するかは、アプリのトラフィックとテナントの数に依存すると思います。個別の接続プールを使用すると、1つのテナントで使用できる接続の量が大幅に少なくなるため、正当な理由で1つのテナントが突然多くの接続を必要とする場合、この特定のテナントで見られるパフォーマンスは大幅に低下します(他のテナントは低下しません)。影響を受ける)。
一方、戦略3では、何らかの正当な理由で1つのテナントが突然多くの接続を必要とする場合、すべてのテナントで見られるパフォーマンスが低下します。
一般に、戦略2はより柔軟で安全だと思います。すべてのテナントは、指定された量を超える接続を消費することはできません(必要に応じて、この量をテナントごとに構成できます)