Sie können zwischen 3 verschiedenen Strategien wählen, die sich auf die Verbindungsabfrage auswirken. In jedem Fall müssen Sie eine Implementierung von MultiTenantConnectionProvider
bereitstellen . Die von Ihnen gewählte Strategie wirkt sich natürlich auf Ihre Implementierung aus.
Allgemeine Anmerkung zu MultiTenantConnectionProvider.getAnyConnection()
getAnyConnection()
wird von Hibernate benötigt, um Metadaten zu sammeln und die SessionFactory einzurichten. Normalerweise haben Sie in einer Multi-Tenant-Architektur eine spezielle/Master-Datenbank (oder ein Schema), die von keinem Tenant verwendet wird. Es ist eine Art Vorlagendatenbank (oder Schema). Es ist in Ordnung, wenn diese Methode eine Verbindung zu dieser Datenbank (oder diesem Schema) zurückgibt.
Strategie 1:Jeder Mieter hat seine eigene Datenbank. (und somit ein eigener Verbindungspool)
In diesem Fall hat jeder Mandant seinen eigenen Verbindungspool, der von C3PO verwaltet wird, und Sie können eine Implementierung von MultiTenantConnectionProvider
bereitstellen basierend auf AbstractMultiTenantConnectionProvider
Jeder Mandant hat seinen eigenen C3P0ConnectionProvider
, also alles, was Sie in selectConnectionProvider(tenantIdentifier)
tun müssen ist, das richtige zurückzugeben. Sie können eine Map behalten, um sie zwischenzuspeichern, und Sie können einen C3POConnectionProvider mit so etwas wie :
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=...
// ...)
}
Strategie 2:Jeder Mandant hat sein eigenes Schema und seinen eigenen Verbindungspool in einer einzigen Datenbank
Dieser Fall ist der ersten Strategie bezüglich ConnectionProvider
sehr ähnlich da Sie auch AbstractMultiTenantConnectionProvider
verwenden können als Basisklasse zum Implementieren Ihres MultiTenantConnectionProvider
Die Implementierung ist der vorgeschlagenen Implementierung für Strategie 1 sehr ähnlich, außer dass Sie das Schema anstelle der Datenbank in der c3po-Konfiguration ändern müssen
Strategie 3:Jeder Mandant hat sein eigenes Schema in einer einzelnen Datenbank, verwendet aber einen gemeinsam genutzten Verbindungspool
Dieser Fall ist etwas anders, da jeder Mandant denselben Verbindungsanbieter verwendet (und somit der Verbindungspool gemeinsam genutzt wird). In dem Fall:Der Verbindungsanbieter muss das zu verwendende Schema vor jeder Verwendung der Verbindung festlegen. d.h. Sie müssen MultiTenantConnectionProvider.getConnection(String tenantIdentifier)
implementieren (d. h. die von AbstractMultiTenantConnectionProvider
bereitgestellte Standardimplementierung funktioniert nicht).
Mit postgresql können Sie dies mit :
tun SET search_path to <schema_name_for_tenant>;
oder mit dem Alias
SET schema <schema_name_for_tenant>;
Hier ist also Ihr getConnection(tenant_identifier);
sieht so aus:
@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;
}
Nützliche Referenzen finden Sie hier (offizielles Dokument)
Anderer nützlicher Link C3POConnectionProvider.java
Sie können Strategie 1 und Strategie 2 in Ihrer Implementierung kombinieren. Sie brauchen nur eine Möglichkeit, die richtigen Verbindungseigenschaften/Verbindungs-URL für den aktuellen Mandanten zu finden.
BEARBEITEN
Ich denke, dass die Wahl zwischen Strategie 2 oder 3 vom Datenverkehr und der Anzahl der Mandanten in Ihrer App abhängt. Mit getrennten Verbindungspools:Die Anzahl der für einen Mandanten verfügbaren Verbindungen ist viel geringer, und so:Wenn aus irgendeinem berechtigten Grund ein Mandant plötzlich viele Verbindungen benötigt, wird die Leistung, die dieser bestimmte Mandant sieht, drastisch abnehmen (während dies beim anderen Mandant nicht der Fall ist). betroffen).
Wenn andererseits bei Strategie 3 aus irgendeinem berechtigten Grund ein Mandant plötzlich viele Verbindungen benötigt:Die Leistung, die jeder Mandant sieht, wird abnehmen.
Im Allgemeinen denke ich, dass Strategie 2 flexibler und sicherer ist:Jeder Mandant kann nicht mehr als eine bestimmte Verbindungsmenge verbrauchen (und diese Menge kann pro Mandant konfiguriert werden, wenn Sie es brauchen)