Можете да избирате между 3 различни стратегии, които ще повлияят на анкетирането на връзката. Във всеки случай трябва да предоставите реализация на MultiTenantConnectionProvider
. Стратегията, която изберете, разбира се, ще повлияе на изпълнението ви.
Обща забележка относно MultiTenantConnectionProvider.getAnyConnection()
getAnyConnection()
се изисква от hibernate за събиране на метаданни и настройка на SessionFactory. Обикновено в архитектура с множество наематели имате специална/главна база данни (или схема), която не се използва от никой наемател. Това е един вид шаблонна база данни (или схема). Добре е, ако този метод върне връзка към тази база данни (или схема).
Стратегия 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
Изпълнението е много подобно на предложеното изпълнение за Стратегия 1, с изключение на това, че трябва да промените схемата вместо базата данни в конфигурацията c3po
Стратегия 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 зависи от трафика и броя на наемателите на вашето приложение. С отделни пулове за връзки:количеството връзки, налични за един наемател, ще бъде много по-малко и така:ако по някаква законна причина един наемател изведнъж се нуждае от много връзки, производителността, наблюдавана от този конкретен наемател, ще намалее драстично (докато другият наемател няма да бъде засегнати).
От друга страна, със стратегия 3, ако по някаква законна причина един наемател изведнъж се нуждае от много връзки:производителността, наблюдавана от всеки наемател, ще намалее.
Като цяло смятам, че стратегия 2 е по-гъвкава и безопасна:всеки наемател не може да консумира повече от определено количество връзка (и това количество може да бъде конфигурирано за наемател, ако имате нужда от него)