מדריך למולטי ריביות במצב שינה

1. הקדמה

ריבוי מודעות מאפשר ללקוחות או דיירים מרובים להשתמש במשאב יחיד או, בהקשר של מאמר זה, במופע בסיסי יחיד. המטרה היא לבודד את המידע שכל דייר זקוק לו ממסד הנתונים המשותף.

במדריך זה נציג גישות שונות לקביעת תצורה של ריבוי רביעיות ב- Hibernate 5.

2. תלות Maven

נצטרך לכלול את ה- ליבת שינה תלות ב pom.xml קוֹבֶץ:

 org.hibernate hibernate-core 5.2.12.Final 

לבדיקה נשתמש במאגר נתונים בזיכרון H2, אז בואו גם להוסיף תלות זו ל- pom.xml קוֹבֶץ:

 com.h2database h2 1.4.196 

3. הבנת ריבוי מידות במצב שינה

כפי שהוזכר במדריך המשתמש הרשמי למצב שינה, ישנן שלוש גישות למולטי-ריביות במצב שינה:

  • סכמה נפרדת - סכימה אחת לכל דייר באותו מופע בסיסי פיזי
  • מסד נתונים נפרד - מופע בסיסי נפרד של בסיס נתונים לכל דייר
  • נתונים מחולקים (מפלה) - הנתונים עבור כל דייר מחולקים לפי ערך מפלה

ה גישת נתונים מחולקת (מפלה) עדיין לא נתמכת על ידי מצב שינה. עקוב אחר נושא JIRA זה להתקדמות עתידית.

כרגיל, מצב שינה ממצה את המורכבות סביב יישום כל גישה.

כל מה שאנחנו צריכים זה לספק יישום של שני ממשקים אלה:

  • MultiTenantConnectionProvider - מספק חיבורים לדייר

  • CurrentTenantIdentifierResolver - פותר את מזהה הדייר לשימוש

בואו נראה יותר בפירוט כל מושג לפני שעוברים על דוגמאות הגישה למאגר והסכמה.

3.1.MultiTenantConnectionProvider

בעיקרון, ממשק זה מספק חיבור בסיס נתונים למזהה דייר קונקרטי.

בואו נראה את שתי השיטות העיקריות שלה:

ממשק MultiTenantConnectionProvider מרחיב את השירות, עטוף {Connection getAnyConnection () זורק SQLException; Connection getConnection (String tenantIdentifier) ​​זורק SQLException; // ...}

אם מצב שינה אינו מצליח לפתור את מזהה הדייר לשימוש, הוא ישתמש בשיטה getAnyConnection כדי להשיג חיבור. אחרת, הוא ישתמש בשיטה getConnection.

Hibernate מספק שתי יישומים של ממשק זה תלוי באופן הגדרת חיבורי מסד הנתונים:

  • באמצעות ממשק DataSource מג'אווה - היינו משתמשים ב- DataSourceBasedMultiTenantConnectionProviderImpl יישום
  • משתמש ב ConnectionProvider ממשק ממצב שינה - היינו משתמשים ב- תקציר MultiTenantConnectionProvider יישום

3.2.CurrentTenantIdentifierResolver

יש דרכים רבות אפשריות לפתור מזהה דייר. לדוגמה, היישום שלנו יכול להשתמש במזהה דייר אחד שהוגדר בקובץ תצורה.

דרך אחרת יכולה להיות שימוש במזהה הדייר מפרמטר נתיב.

בואו נראה את הממשק הזה:

ממשק ציבורי CurrentTenantIdentifierResolver {String resolutionCurrentTenantIdentifier (); validateExisteingCurrentSessions () בוליאני; }

מצב שינה מכנה את השיטה resolCurrentTenantIdentifier כדי לקבל את מזהה הדייר. אם אנו רוצים ש- 'שינה' יאמת את כל ההפעלות הקיימות שייכות לאותו מזהה דייר, השיטה validateExistingCurrentSessions צריך לחזור אמיתי.

4. גישת סכמה

באסטרטגיה זו נשתמש בסכמות או משתמשים שונים באותו מופע בסיסי של מסד נתונים. יש להשתמש בגישה זו כאשר אנו זקוקים לביצועים הטובים ביותר עבור היישום שלנו ויכולים להקריב תכונות מסדי נתונים מיוחדות כגון גיבוי למשתכן.

כמו כן, נלעוג ל CurrentTenantIdentifierResolver ממשק כדי לספק מזהה דייר אחד כבחירתנו במהלך הבדיקה:

מעמד מופשט ציבורי MultitenancyIntegrationTest {@Mock פרטי CurrentTenantIdentifierResolver currentTenantIdentifierResolver; SessionFactory פרטית sessionFactory; @ לפני התקנת הריק הציבורי () זורק את IOException {MockitoAnnotations.initMocks (זה); כאשר (currentTenantIdentifierResolver.validateExistingCurrentSessions ()) .thenReturn (false); מאפייני מאפיינים = getHibernateProperties (); properties.put (AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolver); sessionFactory = buildSessionFactory (מאפיינים); initTenant (TenantIdNames.MYDB1); initTenant (TenantIdNames.MYDB2); } initTenant מוגן ריק (String tenantId) {when (currentTenantIdentifierResolver .resolveCurrentTenantIdentifier ()) .thenReturn (tenantId); createCarTable (); }}

היישום שלנו של MultiTenantConnectionProvider ממשק יהיה הגדר את הסכימה שתשתמש בה בכל פעם שמתבקש חיבור:

class SchemaMultiTenantConnectionProvider מרחיב AbstractMultiTenantConnectionProvider {private ConnectionProvider connectionProvider; SchemaMultiTenantConnectionProvider ציבורי () זורק IOException {this.connectionProvider = initConnectionProvider (); } ConnectionProvider מוגן @ @ Override getAnyConnectionProvider () {return connectionProvider; } @Override מוגן ConnectionProvider selectConnectionProvider (String tenantIdentifier) ​​{return connectionProvider; } @Override Public Connection getConnection (מחרוזת tenantIdentifier) ​​זורק SQLException {Connection connection = super.getConnection (tenantIdentifier); connection.createStatement () .execute (String.format ("SET SCHEMA% s;", tenantIdentifier)); חיבור חזרה; } ConnectionProvider פרטית initConnectionProvider () זורק IOException {מאפייני מאפיינים = מאפיינים חדשים (); properties.load (getClass () .getResourceAsStream ("/ hibernate.properties")); DriverManagerConnectionProviderImpl connectionProvider = DriverManagerConnectionProviderImpl חדש (); connectionProvider.configure (מאפיינים); החזר חיבור ספק; }}

לכן נשתמש במסד נתונים H2 בזיכרון עם שתי סכמות - אחת לכל דייר.

בואו להגדיר את hibernate.properties להשתמש במצב ריבוי סכמות והטמעה שלנו MultiTenantConnectionProvider מִמְשָׁק:

hibernate.connection.url = jdbc: h2: mem: mydb1; DB_CLOSE_DELAY = -1; \ INIT = צור סכימה אם לא קיים MYDB1 \; צור סכימה אם לא קיים MYDB2 \; hibernate.multiTenancy = SCHEMA hibernate.multi_tenant_connection_provider = \ com.baeldung.hibernate.multitenancy.schema.SchemaMultiTenantConnectionProvider

לצורך הבדיקה שלנו, הגדרנו את ה- hibernate.connection.url נכס ליצירת שתי סכמות. זה לא צריך להיות נחוץ ליישום אמיתי מכיוון שהתכניות צריכות להיות קיימות כבר.

לבדיקה שלנו, נוסיף אחד אוטו כניסה לדייר myDb1. אנו נוודא שהערך הזה נשמר במסד הנתונים שלנו ושהוא לא נמצא אצל הדייר myDb2:

@Test בטל כאשרAddingEntries_thenOnlyAddedToConcreteDatabase () {whenCurrentTenantIs (TenantIdNames.MYDB1); whenAddCar ("myCar"); thenCarFound ("myCar"); whenCurrentTenantIs (TenantIdNames.MYDB2); thenCarNotFound ("myCar"); }

כפי שאנו רואים במבחן, אנו מחליפים את הדייר בעת קריאה ל- whenCurrentTenantIs שיטה.

5. גישת מסד נתונים

הגישה מרובת הדיירים של מסד הנתונים משתמשת מופעי מסד נתונים פיזיים שונים לדייר. מכיוון שכל דייר מבודד לחלוטין, עלינו לבחור באסטרטגיה זו כאשר אנו זקוקים לתכונות מסד נתונים מיוחדות כמו גיבוי למשתכן יותר ממה שאנו זקוקים לביצועים הטובים ביותר.

לגישת מסד הנתונים, נשתמש באותה מידה MultitenancyIntegrationTest הכיתה וה CurrentTenantIdentifierResolver ממשק כנ"ל.

בשביל ה MultiTenantConnectionProvider ממשק, נשתמש ב- מַפָּה אוסף כדי להשיג א ConnectionProvider למזהה דייר:

class MapMultiTenantConnectionProvider מרחיב AbstractMultiTenantConnectionProvider {private map connectionProviderMap = HashMap חדש (); MapMultiTenantConnectionProvider () זורק IOException {initConnectionProviderForTenant (TenantIdNames.MYDB1); initConnectionProviderForTenant (TenantIdNames.MYDB2); } @Override מוגן ConnectionProvider getAnyConnectionProvider () {return connectionProviderMap.values ​​() .iterator () .next (); } @ Override מוגן ConnectionProvider selectConnectionProvider (מחרוזת tenantIdentifier) ​​{להחזיר connectionProviderMap.get (tenantIdentifier); } ריק ריק initConnectionProviderForTenant (מחרוזת tenantId) זורק IOException {מאפייני מאפיינים = מאפיינים חדשים (); properties.load (getClass (). getResourceAsStream (String.format ("/ hibernate-database-% s.properties", tenantId))); DriverManagerConnectionProviderImpl connectionProvider = DriverManagerConnectionProviderImpl חדש (); connectionProvider.configure (מאפיינים); this.connectionProviderMap.put (tenantId, connectionProvider); }}

כל אחד ConnectionProvider מאוכלס באמצעות קובץ התצורה hibernate-database-.properties, שיש בו את כל פרטי החיבור:

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

לבסוף, בואו נעדכן את hibernate.properties שוב כדי להשתמש במצב ריבוי מסדי נתונים וביישום שלנו MultiTenantConnectionProvider מִמְשָׁק:

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

אם אנו מבצעים את אותו הבדיקה בדיוק כמו בגישת הסכימה, הבדיקה עוברת שוב.

6. מסקנה

מאמר זה מכסה תמיכה ב- Hibernate 5 למולטי-טיים באמצעות בסיס הנתונים הנפרד וגישות הסכימה הנפרדות. אנו מספקים יישומים פשוטים מאוד ודוגמאות לבדיקת ההבדלים בין שתי אסטרטגיות אלה.

דוגמאות הקוד המלאות המשמשות במאמר זה זמינות בפרויקט GitHub שלנו.


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