Du kan vælge mellem 3 forskellige strategier, der vil påvirke forbindelsesafstemningen. Under alle omstændigheder skal du levere en implementering af MultiTenantConnectionProvider
. Den strategi, du vælger, vil selvfølgelig påvirke din implementering.
Generel bemærkning om MultiTenantConnectionProvider.getAnyConnection()
getAnyConnection()
er påkrævet af dvale for at indsamle metadata og opsætte SessionFactory. Normalt i en multi-tenant-arkitektur har du en speciel/masterdatabase (eller et skema), der ikke bruges af nogen lejer. Det er en slags skabelondatabase (eller skema). Det er ok, hvis denne metode returnerer en forbindelse til denne database (eller skema).
Strategi 1:hver lejer har sin egen database. (og så det er egen forbindelsespulje)
I dette tilfælde har hver lejer sin egen forbindelsespulje, der administreres af C3PO, og du kan levere en implementering af MultiTenantConnectionProvider
baseret på AbstractMultiTenantConnectionProvider
Hver lejer har sin egen C3P0ConnectionProvider
, så alt hvad du skal gøre i selectConnectionProvider(tenantIdentifier)
er at returnere den rigtige. Du kan beholde et kort for at cache dem, og du kan doven-initialisere en C3POConnectionProvider med noget som:
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=...
// ...)
}
Strategi 2 :hver lejer har sit eget skema og sin egen forbindelsespulje i en enkelt database
Denne sag minder meget om den første strategi vedrørende ConnectionProvider
implementering, da du også kan bruge AbstractMultiTenantConnectionProvider
som basisklasse for at implementere din MultiTenantConnectionProvider
Implementeringen ligner meget den foreslåede implementering for Strategi 1, bortset fra at du skal ændre skemaet i stedet for databasen i c3po-konfigurationen
Strategi 3 :hver lejer har sit eget skema i en enkelt database, men brug en delt forbindelsespulje
Denne sag er lidt anderledes, da hver lejer vil bruge den samme forbindelsesudbyder (og derfor vil forbindelsespuljen blive delt). I tilfældet :Forbindelsesudbyderen skal indstille skemaet til brug før enhver brug af forbindelsen. dvs. du skal implementere MultiTenantConnectionProvider.getConnection(String tenantIdentifier)
(dvs. standardimplementeringen leveret af AbstractMultiTenantConnectionProvider
virker ikke).
Med postgresql kan du gøre det med :
SET search_path to <schema_name_for_tenant>;
eller ved at bruge aliaset
SET schema <schema_name_for_tenant>;
Så her er hvad din getConnection(tenant_identifier);
vil se sådan ud:
@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;
}
Nyttig reference er her (officielt dokument)
Andet nyttigt link C3POConnectionProvider.java
Du kan kombinere strategi 1 og strategi 2 i din implementering. Du mangler bare en måde at finde de korrekte forbindelsesegenskaber/forbindelses-url for den nuværende lejer.
REDIGER
Jeg tror, at valget mellem strategi 2 eller 3 afhænger af trafikken og antallet af lejere på din app. Med separate forbindelsespuljer:mængden af tilgængelige forbindelser for én lejer vil være meget lavere, og så:hvis én lejer af en eller anden legitim grund pludselig har brug for mange forbindelser, vil ydeevnen set af denne bestemte lejer falde drastisk (mens den anden lejer ikke vil påvirket).
På den anden side, med strategi 3, hvis én lejer af en eller anden legitim grund pludselig har brug for mange forbindelser:den præstation, som hver lejer ser, vil falde.
Generelt synes jeg, at strategi 2 er mere fleksibel og sikker:hver lejer kan ikke forbruge mere end en given mængde forbindelse (og dette beløb kan konfigureres pr. lejer, hvis du har brug for det)