Útmutató a hibás állapotú multitenanciához 5
1. Bemutatkozás
A Multitenancy lehetővé teszi, hogy több ügyfél vagy bérlő használjon egyetlen erőforrást, vagy a cikk kapcsán egyetlen adatbázis-példányt. A cél az az egyes bérlők számára szükséges információk elkülönítése a megosztott adatbázistól.
Ebben az oktatóanyagban különböző megközelítéseket mutatunk be a multitenancy beállításához a Hibernate 5-ben.
2. Maven-függőségek
Be kell foglalnunk a hibernált mag függőség a pom.xml fájl:
org.hibernate hibernate-core 5.2.12.Végső
A teszteléshez H2 memóriában lévő adatbázist fogunk használni, ezért adjuk hozzá ezt a függőséget is a pom.xml fájl:
com.h2adatbázis h2 1.4.196
3. A multitenancia megértése hibernált állapotban
Amint a hivatalos hibernált felhasználói útmutatóban említettük, a hibernált állapotban háromféle megközelítés létezik:
- Külön séma - bérlőnként egy séma ugyanabban a fizikai adatbázis-példányban
- Külön adatbázis - bérlőnként egy külön fizikai adatbázis-példány
- Particionált (diszkriminátor) adatok - az egyes bérlők adatait egy diszkriminátor érték osztja fel
A A Hibernate még nem támogatja a particionált (diszkriminátor) adat megközelítést. A jövőbeli előrehaladás érdekében kövesse nyomon ezt a JIRA-kérdést.
Szokás szerint a Hibernate elvonatkoztatja az egyes megközelítések megvalósításának bonyolultságát.
Csak arra van szükségünk biztosítja ennek a két interfésznek a megvalósítását:
MultiTenantConnectionProvider - bérlőnként biztosítja a kapcsolatokat
CurrentTenantIdentifierResolver - feloldja a bérlő azonosítóját használni
Lássuk részletesebben az egyes fogalmakat, mielőtt végignéznénk az adatbázis és a séma megközelítési példákat.
3.1.MultiTenantConnectionProvider
Alapvetően ez a felület adatbázis-kapcsolatot biztosít egy konkrét bérlő-azonosító számára.
Nézzük meg két fő módszerét:
interfész A MultiTenantConnectionProvider kiterjeszti a szolgáltatást, a Wrapped {Connection getAnyConnection () dobja az SQLException-t; Connection getConnection (String tenantIdentifier) dobja az SQLException-t; // ...}
Ha a hibernálás nem tudja megoldani a bérlő azonosítóját, akkor a módszert használja getAnyConnection hogy kapcsolatot szerezzek. Ellenkező esetben a módszert fogja használni getConnection.
A hibernálás ennek a felületnek két megvalósítását biztosítja attól függően, hogy hogyan definiáljuk az adatbázis-kapcsolatokat:
- A Java-ból származó DataSource felület használata - a DataSourceBasedMultiTenantConnectionProviderImpl végrehajtás
- Használni a ConnectionProvider interfész Hibernate-től - a AbstractMultiTenantConnectionProvider végrehajtás
3.2.CurrentTenantIdentifierResolver
Vannak a bérlő azonosítójának feloldásának számos lehetséges módja. Például megvalósításunk egy konfigurációs fájlban definiált bérlői azonosítót használhat.
Egy másik módszer lehet a bérlő azonosítójának használata egy útparaméterből.
Lássuk ezt a felületet:
nyilvános felület CurrentTenantIdentifierResolver {String ResolCurrentTenantIdentifier (); logikai validateExistingCurrentSessions (); }
Hibernate hívja a módszert resolCurrentTenantIdentifier hogy megkapja a bérlő azonosítóját. Ha azt akarjuk, hogy a Hibernate validálja az összes létező munkamenetet, ugyanahhoz a bérlő azonosítóhoz tartozik, a módszer validateExistingCurrentSessions vissza kell térnie igaznak.
4. Séma megközelítés
Ebben a stratégiában különböző sémákat vagy felhasználókat fogunk használni ugyanabban a fizikai adatbázis-példányban. Ezt a megközelítést akkor kell alkalmazni, ha a legjobb teljesítményre van szükségünk az alkalmazásunkhoz, és feláldozhatja a speciális adatbázis-szolgáltatásokat, például a bérlőnkénti biztonsági mentést.
Ezenkívül megcsúfoljuk a CurrentTenantIdentifierResolver interfész egy bérlő azonosító megadásához, amelyet a teszt során választottunk:
public abstract class MultitenancyIntegrationTest {@Mock private CurrentTenantIdentifierResolver currentTenantIdentifierResolver; privát SessionFactory sessionFactory; @A nyilvános void beállítása előtt () az IOException dobja {MockitoAnnotations.initMocks (this); mikor (currentTenantIdentifierResolver.validateExistingCurrentSessions ()) .thenReturn (hamis); Tulajdonságok tulajdonságai = getHibernateProperties (); tulajdonságok.put (AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolver); sessionFactory = buildSessionFactory (tulajdonságok); initTenant (TenantIdNames.MYDB1); initTenant (TenantIdNames.MYDB2); } protected void initTenant (String tenantId) {mikor (currentTenantIdentifierResolver .resolveCurrentTenantIdentifier ()) .thenReturn (tenantId); createCarTable (); }}
A MultiTenantConnectionProvider interfész lesz állítsa be a sémát arra, hogy minden alkalommal használja a kapcsolatot:
class SchemaMultiTenantConnectionProvider kiterjeszti az AbstractMultiTenantConnectionProvider {private ConnectionProvider connectionProvider; public SchemaMultiTenantConnectionProvider () dobja az IOException-t {this.connectionProvider = initConnectionProvider (); } @Orride védett ConnectionProvider getAnyConnectionProvider () {return connectionProvider; } @Orride védett ConnectionProvider selectConnectionProvider (String tenantIdentifier) {return connectionProvider; } @Orride public Connection getConnection (String tenantIdentifier) dobja az SQLException {Connection connection = super.getConnection (tenantIdentifier); connection.createStatement () .execute (String.format ("SET SCHEMA% s;", tenantIdentifier)); visszatérő kapcsolat; } private ConnectionProvider initConnectionProvider () dobja az IOException {Properties tulajdonságok = new Properties (); tulajdonságok.load (getClass () .getResourceAsStream ("/ hibernate.properties")); DriverManagerConnectionProviderImpl connectionProvider = új DriverManagerConnectionProviderImpl (); connectionProvider.configure (tulajdonságok); return connectionProvider; }}
Tehát egy memóriában lévő H2 adatbázist fogunk használni, két sémával - bérlőnként egyet.
Konfiguráljuk a hibernálni.tulajdonságok a séma multitenancy mód használatához és a MultiTenantConnectionProvider felület:
hibernate.connection.url = jdbc: h2: mem: mydb1; DB_CLOSE_DELAY = -1; \ INIT = Séma létrehozása, ha nem létezik MYDB1 \; Séma létrehozása, ha nem létezik MYDB2 \; hibernate.multiTenancy = SCHEMA hibernate.multi_tenant_connection_provider = \ com.baeldung.hibernate.multitenancy.schema.SchemaMultiTenantConnectionProvider
Tesztünk céljából konfiguráltuk a hibernálni.kapcsolat.url tulajdonság két séma létrehozásához. Erre nincs szükség egy valódi alkalmazáshoz, mivel a sémáknak már meg kell lenniük.
Tesztünkhöz hozzáadunk egyet Autó bejegyzés a bérlőbe myDb1. Ellenőrizzük, hogy ezt a bejegyzést tárolták-e az adatbázisunkban, és hogy nincs-e a bérlőnél myDb2:
@Test void whenAddingEntries_thenOnlyAddedToConcreteDatabase () {whenCurrentTenantIs (TenantIdNames.MYDB1); mikorAddCar ("myCar"); thenCarFound ("myCar"); whenCurrentTenantIs (TenantIdNames.MYDB2); thenCarNotFound ("myCar"); }
Mint a teszten láthatjuk, a bérlőt megváltoztatjuk, amikor felhívjuk a whenCurrentTenantIs módszer.
5. Adatbázis megközelítés
Az Adatbázis több bérleti megközelítés használja bérlőnként különböző fizikai adatbázis-példányok. Mivel minden bérlő teljesen elszigetelődött, akkor kell ezt a stratégiát választanunk, ha speciális adatbázis-funkciókra van szükségünk, például bérlőnkénti biztonsági mentésre, mint amennyire a legjobb teljesítményre van szükségünk.
Az adatbázis megközelítésnél ugyanezt fogjuk használni MultitenancyIntegrationTest osztály és a CurrentTenantIdentifierResolver felület, mint fent.
A MultiTenantConnectionProvider felületen használjuk a Térkép gyűjtemény, hogy a ConnectionProvider bérlői azonosítónként:
class MapMultiTenantConnectionProvider kiterjeszti az AbstractMultiTenantConnectionProvider {privát Map connectionProviderMap = új HashMap (); public MapMultiTenantConnectionProvider () dobja az IOException {initConnectionProviderForTenant (TenantIdNames.MYDB1); initConnectionProviderForTenant (TenantIdNames.MYDB2); } @Orride védett ConnectionProvider getAnyConnectionProvider () {return connectionProviderMap.values () .iterator () .next (); } @Orride védett ConnectionProvider selectConnectionProvider (String tenantIdentifier) {return connectionProviderMap.get (tenantIdentifier); } private void initConnectionProviderForTenant (String tenantId) dobja az IOException {Properties properties = new Properties (); tulajdonságok.load (getClass (). getResourceAsStream (String.format ("/ hibernate-database-% s.properties", tenantId)); DriverManagerConnectionProviderImpl connectionProvider = új DriverManagerConnectionProviderImpl (); connectionProvider.configure (tulajdonságok); this.connectionProviderMap.put (tenantId, connectionProvider); }}
Minden egyes ConnectionProvider a konfigurációs fájlon keresztül kerül feltöltésre hibernate-database-.properties, amely az összes csatlakozási adattal rendelkezik:
hibernate.connection.driver_class = org.h2.Driver hibernate.connection.url = jdbc: h2: mem:; DB_CLOSE_DELAY = -1 hibernate.connection.username = sa hibernate.dialect = org.hibernate.dialect.H2Dialect
Végül frissítsük a hibernálni.tulajdonságok ismét használhatja az adatbázis multitenancy módot és a MultiTenantConnectionProvider felület:
hibernate.multiTenancy = DATABASE hibernate.multi_tenant_connection_provider = \ com.baeldung.hibernate.multitenancy.database.MapMultiTenantConnectionProvider
Ha pontosan ugyanazt a tesztet futtatjuk, mint a séma megközelítésnél, akkor a teszt újra sikeres lesz.
6. Következtetés
Ez a cikk a Hibernate 5 támogatását tárgyalja a különféle adatbázisok és a különálló séma megközelítések használatával. Nagyon leegyszerűsített megvalósításokat és példákat kínálunk a két stratégia közötti különbségek feltárására.
A cikkben használt teljes kódminták elérhetők a GitHub projektünkön.