המטמון של Hibernate – מטמון רמה ראשונה

ברוכים הבאים לשימוש במטמון Hibernate – הדוגמה הראשונה של הדרכה. לאחרונה בידקנו את ארכיטקטורת Hibernate, מיפוי Hibernate וכיצד להשתמש ב־HQL כדי לבצע שאילתות SQL בדרך המונה. היום נביט באחד מהנושאים החשובים של Hibernate – המטמון של Hibernate.

המטמון של Hibernate

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

  1. מטמון רמה ראשונה: מטמון רמה ראשונה של Hibernate מקושר עם אובייקט Session. מטמון רמה ראשונה של Hibernate מופעל כברירת מחדל ואין דרך לבטל אותו. אך Hibernate מספקת שיטות באמצעותן ניתן למחוק אובייקטים נבחרים מהמטמון או לנקות את המטמון לחלוטין. כל אובייקט שמאוחסן בסשן לא יהיה גלוי לסשנים אחרים וכאשר הסשן נסגר, כל האובייקטים שנאחסנו יאבדו גם כן.
  2. מטמון רמה שנייה: מטמון רמה שנייה של Hibernate מושבת כברירת מחדל, אך ניתן להפעיל אותו דרך התקנת התצורה. כרגע, EHCache ו-Infinispan מספקים יישום למטמון רמה שנייה של Hibernate וניתן להשתמש בהם. נבחן זאת בשורה הבאה של הדרכה למטמון של Hibernate.
  3. מטמון שאילתות: Hibernate יכולה גם לאחסן במטמון את תוצאות השאילתה. מטמון השאילתות של Hibernate אינו אוחסן את מצב היישות האמיתית במטמון; הוא אוחסן רק ערכי מזהים ותוצאות של סוגי ערך. לכן יש תמיד להשתמש בו בשילוב עם המטמון של רמה שנייה.

מטמון Hibernate – דוגמה למטמון רמה ראשונה

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

package com.journaldev.hibernate.main;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;

public class HibernateCacheExample {

	public static void main(String[] args) throws InterruptedException {
		
		SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
		Session session = sessionFactory.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		//קבלת עובד עם זיהוי=1
		Employee emp = (Employee) session.load(Employee.class, new Long(1));
		printData(emp,1);
		
		//ממתין מספר זמן לשינוי הנתונים ברקע
		Thread.sleep(10000);
		
		//אחזור דטה זהה שוב, בדוק את הלוגים ותראה שאין שאילתה שנשלחה
		Employee emp1 = (Employee) session.load(Employee.class, new Long(1));
		printData(emp1,2);
		
		//יצירת סשן חדש
		Session newSession = sessionFactory.openSession();
		//קבלת עובד עם זיהוי=1, notice the logs for query
		Employee emp2 = (Employee) newSession.load(Employee.class, new Long(1));
		printData(emp2,3);
		
		//התחלה: דוגמת הוצאה לפועל להסרת אובייקט ספציפי מהקאש הראשון של היברנייט
		//קבלת עובד עם זיהוי=2, פעם ראשונה ולכן רואים את השאילתה בלוגים
		Employee emp3 = (Employee) session.load(Employee.class, new Long(2));
		printData(emp3,4);
		
		//הוצאת האובייקט של העובד עם זיהוי=1 מהקאש
		session.evict(emp);
		System.out.println("Session Contains Employee with id=1?"+session.contains(emp));

		//מאחר שהאובייקט הוסר מהקאש הראשון, נראה שאיתחול של שאילתה בלוגים
		Employee emp4 = (Employee) session.load(Employee.class, new Long(1));
		printData(emp4,5);
		
		//האובייקט הזה עדיין קיים, ולכן לא נראה שאילתה בלוגים
		Employee emp5 = (Employee) session.load(Employee.class, new Long(2));
		printData(emp5,6);
		//סיום: דוגמת הוצאה לפועל
		
		//התחלה: דוגמת ניקוי להסרת כל מה שבקאש הראשון
		session.clear();
		Employee emp6 = (Employee) session.load(Employee.class, new Long(1));
		printData(emp6,7);
		Employee emp7 = (Employee) session.load(Employee.class, new Long(2));
		printData(emp7,8);
		
		System.out.println("Session Contains Employee with id=2?"+session.contains(emp7));
		
		tx.commit();
		sessionFactory.close();
	}

	private static void printData(Employee emp, int count) {
		System.out.println(count+":: Name="+emp.getName()+", Zipcode="+emp.getAddress().getZipcode());
	}

}

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

Hibernate Configuration loaded
Hibernate serviceRegistry created
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
1:: Name=Pankaj, Zipcode=95129
2:: Name=Pankaj, Zipcode=95129
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
3:: Name=PankajK, Zipcode=95129
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
4:: Name=David, Zipcode=95051
Session Contains Employee with id=1?false
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
5:: Name=Pankaj, Zipcode=95129
6:: Name=David, Zipcode=95051
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
7:: Name=Pankaj, Zipcode=95129
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
8:: Name=David, Zipcode=95051
Session Contains Employee with id=2?true

נקודות חשובות על מטמון הרמות הראשון ב-Hibernate

נקודות חשובות אודפסו מתוך התוכנית למעלה על מטמון הרמות הראשון ב-Hibernate:

  1. מטמון הרמות הראשון ב-Hibernate מופעל כברירת מחדל, אין צורך בהגדרות עבור זה.
  2. מטמון הרמות הראשון ב-Hibernate הוא ספציפי ל-session, ולכן כאשר אנו מקבלים את אותם נתונים ב-session זהה, אין שאילתה מתבצעת, ובניגוד, ב-session אחרת, השאילתה מתבצעת על מנת לטעון את הנתונים.
  3. מטמון הרמות הראשון ב-Hibernate עשוי להכיל ערכים ישנים, כפי שניתן לראות מתוך התוכנית למעלה, בה שיניתי את הערך (שמשמש כשם מ-Pankaj ל-PankajK) במסד נתונים ואף לא התקבל עדכון ב-session זה. אך ב-session אחר, קיבלנו את הערך המעודכן.
  4. ניתן להשתמש בשיטת evict() של session כדי להסיר אובייקט יחיד ממטמון הרמות הראשון ב-Hibernate.
  5. ניתן להשתמש בשיטת clear() של session כדי לנקות את המטמון, כלומר למחוק את כל האובייקטים ממנו.
  6. ניתן להשתמש בשיטת contains() של session כדי לבדוק האם אובייקט נמצא במטמון הרמות הראשון ב-Hibernate, ואם האובייקט נמצא במטמון, היא מחזירה אמת, אחרת היא מחזירה שקר.
  7. מאחר ש-Hibernate ממטמן את כל האובייקטים ב-session מטמון הרמות הראשון, במהלך הפעלת שאילתות גורם או עדכונים באצווה, חשוב לנקות את המטמון בתקופות מסוימות כדי למנוע בעיות בזיכרון.

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

Source:
https://www.digitalocean.com/community/tutorials/hibernate-caching-first-level-cache