Sprievodca multitenanciou v režime dlhodobého spánku 5

1. Úvod

Multitenancy umožňuje viacerým klientom alebo nájomcom používať jeden prostriedok alebo v kontexte tohto článku jednu inštanciu databázy. Účelom je izolovať informácie, ktoré každý nájomník potrebuje, od zdieľanej databázy.

V tomto tutoriáli si predstavíme rôzne prístupy ku konfigurácii multitenancy v režime dlhodobého spánku 5.

2. Maven závislosti

Budeme musieť zahrnúť hibernácia-jadro závislosť v pom.xml spis:

 org.hibernate hibernate-core 5.2.12.Final 

Na testovanie použijeme databázu H2 v pamäti, pridajme teda túto závislosť aj do pom.xml spis:

 com.h2database h2 1.4.196 

3. Porozumenie multitenancy v režime dlhodobého spánku

Ako je uvedené v oficiálnej používateľskej príručke k režimu dlhodobého spánku, v režime dlhodobého spánku existujú tri prístupy k multitenancy:

  • Samostatná schéma - jedna schéma na nájomcu v tej istej inštancii fyzickej databázy
  • Samostatná databáza - jedna samostatná inštancia fyzickej databázy na jedného nájomcu
  • Rozdelené (diskriminujúce) údaje - údaje pre každého nájomcu sú rozdelené podľa diskriminačnej hodnoty

The Hibernate zatiaľ nepodporuje prístup k rozdeleným (diskriminujúcim) údajom. V nadväznosti na toto vydanie JIRA pre ďalší pokrok.

Ako obvykle, v režime dlhodobého spánku abstrahuje zložitosť okolo implementácie každého prístupu.

Všetko, čo potrebujeme, je zabezpečiť implementáciu týchto dvoch rozhraní:

  • MultiTenantConnectionProvider - poskytuje pripojenia na jedného nájomcu

  • CurrentTenantIdentifierResolver - vyrieši identifikátor nájomcu, ktorý sa má použiť

Pozrime sa podrobnejšie na každý koncept predtým, ako prejdeme príkladmi databázy a schém.

3.1.MultiTenantConnectionProvider

Toto rozhranie v zásade poskytuje databázové pripojenie pre konkrétny identifikátor nájomcu.

Pozrime sa na jeho dve hlavné metódy:

rozhranie MultiTenantConnectionProvider rozširuje službu, zabalené {pripojenie getAnyConnection () vyvolá SQLException; Pripojenie getConnection (String tenantIdentifier) ​​vyvolá SQLException; // ...}

Ak Hibernate nedokáže vyriešiť identifikátor nájomcu, ktorý sa má použiť, použije túto metódu getAnyConnection získať spojenie. V opačnom prípade použije túto metódu getConnection.

Hibernate poskytuje dve implementácie tohto rozhrania v závislosti od toho, ako definujeme databázové pripojenia:

  • Pomocou rozhrania DataSource z Javy - by sme použili DataSourceBasedMultiTenantConnectionProviderImpl implementácia
  • Pomocou ConnectionProvider rozhranie z režimu dlhodobého spánku - použili by sme AbstractMultiTenantConnectionProvider implementácia

3.2.CurrentTenantIdentifierResolver

Existujú mnoho možných spôsobov, ako vyriešiť identifikátor nájomcu. Naša implementácia môže napríklad používať jeden identifikátor tenanta definovaný v konfiguračnom súbore.

Ďalším spôsobom môže byť použitie identifikátora nájomcu z parametra cesty.

Pozrime sa na toto rozhranie:

verejné rozhranie CurrentTenantIdentifierResolver {String resolveCurrentTenantIdentifier (); boolean validateExistingCurrentSessions (); }

Hibernácia volá metódu resolveCurrentTenantIdentifier získať identifikátor nájomcu. Ak chceme, aby režim dlhodobého spánku overil, že všetky existujúce relácie patria rovnakému identifikátoru nájomcu, je to metóda validateExistingCurrentSessions by sa mala vrátiť pravda.

4. Schéma

V tejto stratégii použijeme rôzne schémy alebo používateľov v tej istej inštancii fyzickej databázy. Tento prístup by sa mal použiť, keď potrebujeme najlepší výkon našej aplikácie a môžeme obetovať špeciálne funkcie databázy, ako je zálohovanie na jedného nájomcu.

Vysmejeme sa tiež CurrentTenantIdentifierResolver rozhranie poskytujúce jeden identifikátor tenanta podľa nášho výberu počas testu:

verejná abstraktná trieda MultitenancyIntegrationTest {@Mock private CurrentTenantIdentifierResolver currentTenantIdentifierResolver; private SessionFactory sessionFactory; @ Pred public void setup () hodí IOException {MockitoAnnotations.initMocks (this); keď (currentTenantIdentifierResolver.validateExistingCurrentSessions ()) .thenReturn (false); Vlastnosti vlastnosti = getHibernateProperties (); properties.put (AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolver); sessionFactory = buildSessionFactory (vlastnosti); initTenant (TenantIdNames.MYDB1); initTenant (TenantIdNames.MYDB2); } protected void initTenant (String tenantId) {when (currentTenantIdentifierResolver .resolveCurrentTenantIdentifier ()) .thenReturn (tenantId); createCarTable (); }}

Naša implementácia MultiTenantConnectionProvider rozhranie bude nastaviť schému, ktorá sa má použiť vždy, keď sa požaduje pripojenie:

trieda SchemaMultiTenantConnectionProvider rozširuje AbstractMultiTenantConnectionProvider {private ConnectionProvider connectionProvider; public SchemaMultiTenantConnectionProvider () hodí IOException {this.connectionProvider = initConnectionProvider (); } @Override chránený ConnectionProvider getAnyConnectionProvider () {návrat connectionProvider; } @Override chránený ConnectionProvider selectConnectionProvider (reťazec tenantIdentifier) ​​{návrat connectionProvider; } @Override public Connection getConnection (String tenantIdentifier) ​​hodí SQLException {Connection connection = super.getConnection (tenantIdentifier); connection.createStatement () .execute (String.format ("SET SCHEMA% s;", tenantIdentifier)); spätné pripojenie; } private ConnectionProvider initConnectionProvider () vyvolá IOException {Vlastnosti vlastnosti = nové Vlastnosti (); properties.load (getClass () .getResourceAsStream ("/ hibernate.properties")); DriverManagerConnectionProviderImpl connectionProvider = nový DriverManagerConnectionProviderImpl (); connectionProvider.configure (vlastnosti); spiatočné pripojeniePoskytovateľ; }}

Použijeme teda jednu databázu H2 v pamäti s dvoma schémami - jednu pre každého nájomcu.

Poďme nakonfigurovať prezimovať.vlastnosti používať režim multitenancy schémy a našu implementáciu MultiTenantConnectionProvider rozhranie:

hibernate.connection.url = jdbc: h2: mem: mydb1; DB_CLOSE_DELAY = -1; \ INIT = VYTVORIŤ SCHÉMU, AK NEEXISTUJE MYDB1 \; VYTVORIŤ SCHÉMU, AK NEEXISTUJE MYDB2 \; hibernate.multiTenancy = SCHÉMA hibernate.multi_tenant_connection_provider = \ com.baeldung.hibernate.multitenancy.schema.SchemaMultiTenantConnectionProvider

Na účely nášho testu sme nakonfigurovali prezimovať.spojenie.url vlastnosť na vytvorenie dvoch schém. Pre skutočnú aplikáciu by to nemalo byť potrebné, pretože schémy by už mali byť zavedené.

Pre náš test jeden pridáme Auto vstup v nájomcovi myDb1. Overíme, či bol tento záznam uložený v našej databáze a či nie je v nájomcovi myDb2:

@Test void whenAddingEntries_thenOnlyAddedToConcreteDatabase () {whenCurrentTenantIs (TenantIdNames.MYDB1); whenAddCar ("myCar"); thenCarFound ("myCar"); whenCurrentTenantIs (TenantIdNames.MYDB2); thenCarNotFound ("myCar"); }

Ako vidíme v teste, pri volaní na server zmeníme nájomcu whenCurrentTenantIs metóda.

5. Prístup k databáze

Využíva sa prístup databázy s viacerými nájomami rôzne inštancie fyzickej databázy na jedného nájomcu. Pretože je každý nájomník úplne izolovaný, túto stratégiu by sme si mali zvoliť, keď potrebujeme špeciálne funkcie databázy, ako je zálohovanie na jedného nájomcu, viac, ako potrebujeme najlepší výkon.

Pre databázový prístup použijeme to isté MultitenancyIntegrationTest triedy a CurrentTenantIdentifierResolver rozhranie ako je uvedené vyššie.

Pre MultiTenantConnectionProvider rozhranie, použijeme a Mapa zbierka na získanie a ConnectionProvider na identifikáciu nájomcu:

trieda MapMultiTenantConnectionProvider rozširuje AbstractMultiTenantConnectionProvider {private Map connectionProviderMap = new HashMap (); public MapMultiTenantConnectionProvider () hodí IOException {initConnectionProviderForTenant (TenantIdNames.MYDB1); initConnectionProviderForTenant (TenantIdNames.MYDB2); } @Override chránený ConnectionProvider getAnyConnectionProvider () {návrat connectionProviderMap.values ​​() .iterator () .next (); } @Override chránený ConnectionProvider selectConnectionProvider (reťazec tenantIdentifier) ​​{návrat connectionProviderMap.get (tenantIdentifier); } private void initConnectionProviderForTenant (String tenantId) vyvolá IOException {Vlastnosti vlastnosti = nové Vlastnosti (); properties.load (getClass (). getResourceAsStream (String.format ("/ hibernate-database-% s.properties", tenantId))); DriverManagerConnectionProviderImpl connectionProvider = nový DriverManagerConnectionProviderImpl (); connectionProvider.configure (vlastnosti); this.connectionProviderMap.put (tenantId, connectionProvider); }}

Každý ConnectionProvider sa vyplní cez konfiguračný súbor hibernácia-databáza-.vlastnosti, ktorý má všetky podrobnosti o pripojení:

hibernate.connection.driver_class = org.h2. Ovládač hibernate.connection.url = jdbc: h2: mem:; DB_CLOSE_DELAY = -1 hibernate.connection.username = sa hibernate.dialect = org.hibernate.dialect.H2Dialect

Nakoniec aktualizujme prezimovať.vlastnosti opäť použiť režim multitenancy databázy a našu implementáciu MultiTenantConnectionProvider rozhranie:

hibernate.multiTenancy = DATABASE hibernate.multi_tenant_connection_provider = \ com.baeldung.hibernate.multitenancy.database.MapMultiTenantConnectionProvider

Ak spustíme úplne rovnaký test ako v prístupe so schémou, test opäť dopadne.

6. Záver

Tento článok sa zaoberá podporou Hibernate 5 pre multitenancy pomocou prístupu samostatnej databázy a samostatnej schémy. Poskytujeme veľmi zjednodušené implementácie a príklady na skúmanie rozdielov medzi týmito dvoma stratégiami.

Úplné ukážky kódu použité v tomto článku sú k dispozícii v našom projekte GitHub.


$config[zx-auto] not found$config[zx-overlay] not found