En guide til multitenancy i dvale 5

1. Introduktion

Multitenancy tillader flere klienter eller lejere at bruge en enkelt ressource eller i forbindelse med denne artikel en enkelt databaseinstans. Formålet er for at isolere de oplysninger, som hver lejer har brug for, fra den delte database.

I denne vejledning introducerer vi forskellige tilgange til konfiguration af multitenancy i dvale 5.

2. Maven-afhængigheder

Vi bliver nødt til at medtage dvale-kerne afhængighed i pom.xml fil:

 org. dvale-dvale-core 5.2.12.Final 

Til test bruger vi en H2-hukommelsesdatabase, så lad os også tilføje denne afhængighed til pom.xml fil:

 com.h2database h2 1.4.196 

3. Forståelse af multitenancy i dvale

Som nævnt i den officielle dvaletilstandsvejledning er der tre tilgange til multitenancy i dvaletilstand:

  • Separat skema - et skema pr. lejer i den samme fysiske databaseinstans
  • Separat database - en separat fysisk databaseinstans pr. lejer
  • Opdelte (diskriminerende) data - dataene for hver lejer er opdelt efter en diskriminerende værdi

Det Partitioneret (diskriminator) Datatilgang understøttes endnu ikke af dvale. Følg op på dette JIRA-spørgsmål for fremtidige fremskridt.

Som normalt abstraherer dvale kompleksiteten omkring implementeringen af ​​hver tilgang.

Alt, hvad vi har brug for, er at give en implementering af disse to grænseflader:

  • MultiTenantConnectionProvider - giver forbindelser pr. Lejer

  • CurrentTenantIdentifierResolver - løser den lejeridentifikator, der skal bruges

Lad os se mere detaljeret hvert koncept, før vi går gennem eksempler på databasen og skemaet.

3.1.MultiTenantConnectionProvider

Dybest set giver denne grænseflade en databaseforbindelse til en konkret lejeridentifikator.

Lad os se de to vigtigste metoder:

interface MultiTenantConnectionProvider udvider Service, Wrapped {Connection getAnyConnection () kaster SQLException; Connection getConnection (String tenantIdentifier) ​​kaster SQLException; // ...}

Hvis dvaletilstand ikke kan løse den lejeridentifikator, der skal bruges, bruger den metoden getAnyConnection for at få forbindelse. Ellers bruger den metoden getConnection.

Hibernate tilbyder to implementeringer af denne grænseflade, afhængigt af hvordan vi definerer databaseforbindelserne:

  • Brug af DataSource interface fra Java - vi bruger DataSourceBasedMultiTenantConnectionProviderImpl implementering
  • Bruger ConnectionProvider interface fra dvale - vi bruger AbstraktMultiTenantConnectionProvider implementering

3.2.CurrentTenantIdentifierResolver

Der er mange mulige måder at løse en lejeridentifikator på. For eksempel kan vores implementering bruge en lejeridentifikator, der er defineret i en konfigurationsfil.

En anden måde kan være at bruge lejeridentifikatoren fra en styparameter.

Lad os se denne grænseflade:

offentlig grænseflade CurrentTenantIdentifierResolver {String resolutionCurrentTenantIdentifier (); boolsk validateExistingCurrentSessions (); }

Dvaletilstand kalder metoden resolCurrentTenantIdentifier for at få lejeridentifikatoren. Hvis vi ønsker, at dvaletilstand skal validere alle de eksisterende sessioner tilhører den samme lejeridentifikator, er metoden validateExistingCurrentSessions skal vende tilbage sandt.

4. Skema tilgang

I denne strategi bruger vi forskellige skemaer eller brugere i den samme fysiske databaseinstans. Denne tilgang skal bruges, når vi har brug for den bedste ydeevne til vores applikation og kan ofre specielle databasefunktioner såsom backup pr. Lejer.

Vi vil også spotte CurrentTenantIdentifierResolver interface til at give en lejeridentifikator som vores valg under testen:

offentlig abstrakt klasse MultitenancyIntegrationTest {@Mock private CurrentTenantIdentifierResolver currentTenantIdentifierResolver; privat SessionFactory sessionFactory; @Før offentlig ugyldig opsætning () kaster IOException {MockitoAnnotations.initMocks (dette); når (currentTenantIdentifierResolver.validateExistingCurrentSessions ()) .thenReturn (false); Egenskaber egenskaber = getHibernateProperties (); egenskaber.put (AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolver); sessionFactory = buildSessionFactory (egenskaber); initTenant (TenantIdNames.MYDB1); initTenant (TenantIdNames.MYDB2); } beskyttet ugyldigt initTenant (String tenantId) {når (currentTenantIdentifierResolver .resolveCurrentTenantIdentifier ()) .thenReturn (tenantId); createCarTable (); }}

Vores implementering af MultiTenantConnectionProvider interface vil indstil skemaet til at bruge hver gang der kræves en forbindelse:

klasse SchemaMultiTenantConnectionProvider udvider AbstractMultiTenantConnectionProvider {private ConnectionProvider connectionProvider; offentlig SchemaMultiTenantConnectionProvider () kaster IOException {this.connectionProvider = initConnectionProvider (); } @ Override beskyttet ConnectionProvider getAnyConnectionProvider () {return connectionProvider; } @ Override-beskyttet ConnectionProvider selectConnectionProvider (String tenantIdentifier) ​​{return connectionProvider; } @ Override public Connection getConnection (String tenantIdentifier) ​​kaster SQLException {Connection connection = super.getConnection (tenantIdentifier); connection.createStatement () .execute (String.format ("SET SCHEMA% s;", tenantIdentifier)); returforbindelse } privat ConnectionProvider initConnectionProvider () kaster IOException {Properties egenskaber = nye egenskaber (); egenskaber.load (getClass () .getResourceAsStream ("/ hibernate.properties")); DriverManagerConnectionProviderImpl connectionProvider = ny DriverManagerConnectionProviderImpl (); connectionProvider.configure (egenskaber); tilbagevenden forbindelseProvider; }}

Så vi bruger en H2-database i hukommelsen med to skemaer - en pr. Hver lejer.

Lad os konfigurere dvale.egenskaber at bruge skema multitenancy mode og vores implementering af MultiTenantConnectionProvider interface:

hibernate.connection.url = jdbc: h2: mem: mydb1; DB_CLOSE_DELAY = -1; \ INIT = CREATE SCHEMA IF NOT EXISTS MYDB1 \; CREATE SCHEMA IF NOT EXISTS MYDB2 \; hibernate.multiTenancy = SCHEMA hibernate.multi_tenant_connection_provider = \ com.baeldung.hibernate.multitenancy.schema.SchemaMultiTenantConnectionProvider

Med henblik på vores test har vi konfigureret dvale.forbindelse.url ejendom til at oprette to skemaer. Dette bør ikke være nødvendigt for en reel applikation, da skemaerne allerede skal være på plads.

Til vores test tilføjer vi en Bil indrejse i lejeren myDb1. Vi kontrollerer, at denne post blev gemt i vores database, og at den ikke er i lejeren myDb2:

@Test ugyldigt nårAddingEntries_thenOnlyAddedToConcreteDatabase () {whenCurrentTenantIs (TenantIdNames.MYDB1); nårAddCar ("myCar"); thenCarFound ("myCar"); whenCurrentTenantIs (TenantIdNames.MYDB2); thenCarNotFound ("myCar"); }

Som vi kan se i testen, skifter vi lejer, når vi ringer til whenCurrentTenantIs metode.

5. Databasemetode

Database-tilgangen med flere lejebrug bruger forskellige fysiske databaseinstanser pr. lejer. Da hver lejer er fuldt isoleret, vi skal vælge denne strategi, når vi har brug for specielle databasefunktioner som backup pr. lejer mere, end vi har brug for den bedste ydeevne.

Til databasetilgangen bruger vi det samme MultitenancyIntegrationTest klasse og CurrentTenantIdentifierResolver interface som ovenfor.

Til MultiTenantConnectionProvider interface bruger vi en Kort samling for at få en ConnectionProvider pr. lejer-id:

klasse MapMultiTenantConnectionProvider udvider AbstractMultiTenantConnectionProvider {private Map connectionProviderMap = ny HashMap (); public MapMultiTenantConnectionProvider () kaster IOException {initConnectionProviderForTenant (TenantIdNames.MYDB1); initConnectionProviderForTenant (TenantIdNames.MYDB2); } @ Override beskyttet ConnectionProvider getAnyConnectionProvider () {return connectionProviderMap.values ​​() .iterator () .next (); } @ Override beskyttet ConnectionProvider selectConnectionProvider (String tenantIdentifier) ​​{return connectionProviderMap.get (tenantIdentifier); } privat ugyldigt initConnectionProviderForTenant (streng tenantId) kaster IOException {Egenskaber egenskaber = nye egenskaber (); egenskaber.load (getClass (). getResourceAsStream (String.format ("/ hibernate-database-% s.properties", tenantId))); DriverManagerConnectionProviderImpl connectionProvider = ny DriverManagerConnectionProviderImpl (); connectionProvider.configure (egenskaber); this.connectionProviderMap.put (tenantId, connectionProvider); }}

Hver ConnectionProvider udfyldes via konfigurationsfilen dvale-database-.egenskaber, som har alle forbindelsesoplysninger:

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

Lad os endelig opdatere dvale.egenskaber igen for at bruge databasens multitenancy-tilstand og vores implementering af MultiTenantConnectionProvider grænseflade:

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

Hvis vi kører nøjagtigt den samme test som i skematilgangen, går testen igen.

6. Konklusion

Denne artikel dækker Hibernate 5-understøttelse af multitenancy ved hjælp af den separate database og separate skematilgange. Vi leverer meget forenklede implementeringer og eksempler til at undersøge forskellene mellem disse to strategier.

De fulde kodeeksempler, der bruges i denne artikel, er tilgængelige på vores GitHub-projekt.


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