PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Zarządzaj łączeniem połączeń w aplikacji internetowej dla wielu dzierżawców za pomocą Spring, Hibernate i C3P0

Możesz wybrać jedną z 3 różnych strategii, które wpłyną na odpytywanie połączeń. W każdym razie musisz dostarczyć implementację MultiTenantConnectionProvider . Wybrana strategia będzie oczywiście miała wpływ na wdrożenie.

Ogólna uwaga na temat MultiTenantConnectionProvider.getAnyConnection()

getAnyConnection() jest wymagane przez hibernację do zbierania metadanych i konfigurowania SessionFactory. Zwykle w architekturze z wieloma dzierżawcami masz specjalną/główną bazę danych (lub schemat), która nie jest używana przez żadnego dzierżawcę. Jest to rodzaj bazy danych szablonów (lub schematu). W porządku, jeśli ta metoda zwraca połączenie do tej bazy danych (lub schematu).

Strategia 1:każdy najemca ma własną bazę danych. (a więc jest to własna pula połączeń)

W takim przypadku każdy najemca ma własną pulę połączeń zarządzaną przez C3PO i możesz zapewnić implementację MultiTenantConnectionProvider na podstawie AbstractMultiTenantConnectionProvider

Każdy najemca ma swój własny C3P0ConnectionProvider , więc wszystko, co musisz zrobić w selectConnectionProvider(tenantIdentifier) jest zwrócenie właściwego. Możesz zachować mapę, aby je buforować i możesz leniwie zainicjować C3POConnectionProvider za pomocą czegoś takiego:

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=...
    //     ...) 
}

Strategia 2:każdy dzierżawca ma własny schemat i własną pulę połączeń w jednej bazie danych

Ten przypadek jest bardzo podobny do pierwszej strategii dotyczącej ConnectionProvider implementacja, ponieważ możesz również użyć AbstractMultiTenantConnectionProvider jako klasa bazowa do zaimplementowania Twojego MultiTenantConnectionProvider

Implementacja jest bardzo podobna do sugerowanej implementacji dla Strategii 1, z tym wyjątkiem, że musisz zmienić schemat zamiast bazy danych w konfiguracji c3po

Strategia 3:każdy dzierżawca ma własny schemat w jednej bazie danych, ale korzysta ze wspólnej puli połączeń

Ten przypadek jest nieco inny, ponieważ każdy dzierżawca będzie używał tego samego dostawcy połączenia (a więc pula połączeń zostanie udostępniona). W przypadku:dostawca połączenia musi ustawić schemat do użycia przed użyciem połączenia. tzn. musisz zaimplementować MultiTenantConnectionProvider.getConnection(String tenantIdentifier) (tj. domyślna implementacja dostarczona przez AbstractMultiTenantConnectionProvider nie zadziała).

Z postgresql możesz to zrobić za pomocą :

 SET search_path to <schema_name_for_tenant>;

lub używając aliasu

 SET schema <schema_name_for_tenant>;

Oto, co Twój getConnection(tenant_identifier); będzie wyglądać tak:

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

Przydatne informacje znajdują się tutaj (oficjalny dokument)

Inne przydatne łącze C3POConnectionProvider.java

Możesz połączyć strategię 1 i strategię 2 w swoim wdrożeniu. Potrzebujesz tylko sposobu na znalezienie prawidłowych właściwości połączenia/adresu URL połączenia dla bieżącego najemcy.

EDYTUJ

Myślę, że wybór między strategią 2 a 3 zależy od ruchu i liczby najemców w Twojej aplikacji. Z osobnymi pulami połączeń:liczba połączeń dostępnych dla jednego najemcy będzie znacznie mniejsza, a więc:jeśli z jakiegoś uzasadnionego powodu jeden najemca będzie potrzebował nagle wielu połączeń, wydajność widziana przez tego konkretnego najemcę drastycznie spadnie (podczas gdy drugi najemca nie będzie wpływ).

Z drugiej strony, przy strategii 3, jeśli z jakiegoś uzasadnionego powodu jeden najemca potrzebuje nagle wielu połączeń:wydajność obserwowana przez każdego najemcę spadnie.

Ogólnie uważam, że strategia 2 jest bardziej elastyczna i bezpieczna:każdy najemca nie może zużywać więcej niż podana ilość połączenia (a tę ilość można skonfigurować na dzierżawcę, jeśli tego potrzebujesz)



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Kolumny MySQL z DEFAULT NULL - stylistyczny wybór, czy to prawda?

  2. Jak wypełnić brakujące daty w PostgreSQL za pomocą generate_series

  3. Rekordy oparte na kursorach w PostgreSQL

  4. Migracja z MySQL do PostgreSQL

  5. Całkowite ignorowanie stref czasowych w Rails i PostgreSQL