sql >> Databáze >  >> RDS >> PostgreSQL

Spravujte sdružování připojení ve webové aplikaci pro více nájemců pomocí Spring, Hibernate a C3P0

Můžete si vybrat mezi 3 různými strategiemi, které ovlivní dotazování připojení. V každém případě musíte poskytnout implementaci MultiTenantConnectionProvider . Strategie, kterou zvolíte, bude mít samozřejmě vliv na vaši implementaci.

Obecná poznámka o MultiTenantConnectionProvider.getAnyConnection()

getAnyConnection() je vyžadován hibernací ke sběru metadat a nastavení SessionFactory. Obvykle v architektuře s více nájemci máte speciální/hlavní databázi (nebo schéma), kterou nepoužívá žádný tenant. Je to druh databáze šablon (nebo schématu). Je v pořádku, pokud tato metoda vrátí připojení k této databázi (nebo schématu).

Strategie 1:každý tenant má svou vlastní databázi. (a je to tedy vlastní fond připojení)

V tomto případě má každý tenant svůj vlastní fond připojení spravovaný C3PO a vy můžete poskytnout implementaci MultiTenantConnectionProvider založené na AbstractMultiTenantConnectionProvider

Každý tenant má svého vlastního C3P0ConnectionProvider , takže vše, co musíte udělat v selectConnectionProvider(tenantIdentifier) je vrátit ten správný. Můžete si ponechat mapu pro jejich uložení do mezipaměti a můžete líně inicializovat C3POConnectionProvider s něčím jako:

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:každý tenant má své vlastní schéma a vlastní fond připojení v jediné databázi

Tento případ je velmi podobný první strategii týkající se ConnectionProvider implementaci, protože můžete také použít AbstractMultiTenantConnectionProvider jako základní třídu pro implementaci vašeho MultiTenantConnectionProvider

Implementace je velmi podobná navrhované implementaci pro Strategii 1 s tím rozdílem, že v konfiguraci c3po musíte změnit schéma místo databáze

Strategie 3:každý tenant má své vlastní schéma v jedné databázi, ale používá sdílený fond připojení

Tento případ je mírně odlišný, protože každý tenant bude používat stejného poskytovatele připojení (a tak bude sdílený fond připojení). V případě:poskytovatel připojení musí před jakýmkoli použitím připojení nastavit schéma, které se má použít. tj. musíte implementovat MultiTenantConnectionProvider.getConnection(String tenantIdentifier) (tj. výchozí implementace poskytovaná AbstractMultiTenantConnectionProvider nebude fungovat).

S postgresql to můžete udělat pomocí :

 SET search_path to <schema_name_for_tenant>;

nebo pomocí aliasu

 SET schema <schema_name_for_tenant>;

Zde je tedy váš getConnection(tenant_identifier); bude vypadat takto:

@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;
}

Užitečná reference je zde (oficiální dokument)

Další užitečný odkaz C3POConnectionProvider.java

Ve své implementaci můžete kombinovat strategii 1 a strategii 2. Potřebujete pouze způsob, jak najít správné vlastnosti připojení / adresu URL připojení pro aktuálního tenanta.

UPRAVIT

Myslím, že volba mezi strategií 2 nebo 3 závisí na návštěvnosti a počtu nájemců vaší aplikace. Se samostatnými fondy připojení:množství připojení dostupných pro jednoho tenanta bude mnohem nižší, a tak:pokud z nějakého legitimního důvodu jeden tenant potřebuje najednou mnoho připojení, výkon tohoto konkrétního tenanta se drasticky sníží (zatímco druhý tenant nebude ovlivněno).

Na druhou stranu, se strategií 3, pokud z nějakého legitimního důvodu jeden nájemce potřebuje najednou mnoho připojení:výkon, který vidí každý tenant, se sníží.

Obecně si myslím, že strategie 2 je flexibilnější a bezpečnější:každý tenant nemůže spotřebovat více než dané množství připojení (a toto množství lze nakonfigurovat na každého tenanta, pokud to potřebujete)



  1. Jak znovu vytvořit nekonzistentní PostgreSQL Slave

  2. Minimalizace dopadu rozšíření sloupce IDENTITY – část 3

  3. Nahrajte soubor CSV na SQL server

  4. Jeden bezpečnostní systém pro aplikaci, sdružování připojení a PostgreSQL – případ LDAP