Vous pouvez choisir entre 3 stratégies différentes qui auront un impact sur l'interrogation de la connexion. Dans tous les cas, vous devez fournir une implémentation de MultiTenantConnectionProvider
. La stratégie que vous choisissez aura bien sûr un impact sur votre mise en œuvre.
Remarque générale sur MultiTenantConnectionProvider.getAnyConnection()
getAnyConnection()
est requis par hibernate pour collecter les métadonnées et configurer la SessionFactory. Généralement, dans une architecture multi-locataire, vous disposez d'une base de données (ou schéma) spéciale/maître qui n'est utilisée par aucun locataire. C'est une sorte de modèle de base de données (ou schéma). Ce n'est pas grave si cette méthode renvoie une connexion à cette base de données (ou schéma).
Stratégie 1 :chaque locataire a sa propre base de données. (et donc c'est son propre pool de connexion)
Dans ce cas, chaque locataire a son propre pool de connexions géré par C3PO et vous pouvez fournir une implémentation de MultiTenantConnectionProvider
basé sur AbstractMultiTenantConnectionProvider
Chaque locataire a son propre C3P0ConnectionProvider
, donc tout ce que vous avez à faire dans selectConnectionProvider(tenantIdentifier)
est de retourner le bon. Vous pouvez conserver une Map pour les mettre en cache et vous pouvez initialiser paresseusement un C3POConnectionProvider avec quelque chose comme :
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=...
// ...)
}
Stratégie 2 :chaque locataire a son propre schéma et son propre pool de connexion dans une seule base de données
Ce cas est très similaire à la première stratégie concernant ConnectionProvider
mise en œuvre puisque vous pouvez également utiliser AbstractMultiTenantConnectionProvider
comme classe de base pour implémenter votre MultiTenantConnectionProvider
L'implémentation est très similaire à l'implémentation suggérée pour la stratégie 1, sauf que vous devez modifier le schéma au lieu de la base de données dans la configuration c3po
Stratégie 3 :chaque locataire a son propre schéma dans une seule base de données mais utilise un pool de connexion partagé
Ce cas est légèrement différent puisque chaque locataire utilisera le même fournisseur de connexion (et donc le pool de connexion sera partagé). Dans le cas :le fournisseur de connexion doit définir le schéma à utiliser avant toute utilisation de la connexion. c'est-à-dire que vous devez implémenter MultiTenantConnectionProvider.getConnection(String tenantIdentifier)
(c'est-à-dire l'implémentation par défaut fournie par AbstractMultiTenantConnectionProvider
ne fonctionnera pas).
Avec postgresql vous pouvez le faire avec :
SET search_path to <schema_name_for_tenant>;
ou en utilisant l'alias
SET schema <schema_name_for_tenant>;
Voici donc ce que votre getConnection(tenant_identifier);
ressemblera à :
@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;
}
La référence utile est ici (document officiel)
Autre lien utile C3POConnectionProvider.java
Vous pouvez combiner la stratégie 1 et la stratégie 2 dans votre implémentation. Vous avez juste besoin d'un moyen de trouver les propriétés de connexion/l'URL de connexion correctes pour le locataire actuel.
MODIFIER
Je pense que le choix entre la stratégie 2 ou 3 dépend du trafic et du nombre de tenants sur votre app. Avec des pools de connexions séparés :le nombre de connexions disponibles pour un locataire sera beaucoup plus faible et donc :si pour une raison légitime, un locataire a besoin soudainement de nombreuses connexions, les performances vues par ce locataire particulier diminueront considérablement (alors que l'autre locataire ne sera pas impacté).
En revanche, avec la stratégie 3, si pour une raison légitime un locataire a soudainement besoin de plusieurs connexions :les performances vues par chaque locataire diminueront.
En général, je pense que la stratégie 2 est plus flexible et plus sûre :chaque locataire ne peut pas consommer plus qu'une quantité donnée de connexion (et cette quantité peut être configurée par locataire si vous en avez besoin)