1. 程式人生 > >Hibernate(二)一級快取、延遲載入

Hibernate(二)一級快取、延遲載入

一級快取概念:

一級快取又稱為session級別的快取,所以當session關閉時一級快取也會關閉。如果每次查詢或修改資料都到資料庫中進行查詢或修改,當資料量比較大時就會對程式的效能產生比較大的影響。而一級快取正好解決了這一問題。每次對資料進行查詢時先到快取中去查詢所需要的資料,如果快取中有則直接拿過來用,如果沒有再到資料庫中查詢。然後將查詢到的資料往快取中也放一份,以便下一次使用。

而session對資料進行操作的時候並不是直接操作資料庫,而是將資料先放置到一級快取中,當事務提交或者呼叫session.flush()方法是才會正式執行sql語句對資料庫進行操作。

一級快取測試:

先上測試程式碼

package cn.otote.session;

import org.hibernate.Transaction;
import org.hibernate.classic.Session;
import org.junit.jupiter.api.Test;
import cn.otote.entity.User;
import cn.otote.utils.HibernateUtil;

class SessionTest {

	@Test
	void test() {
		//獲取session
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		//開啟事務
		Transaction transaction = session.beginTransaction();
		
		//獲取user物件
		User user = (User) session.get(User.class,1);
		//將user的資訊打印出來
		System.out.println(user);
		
		System.out.println("-----------------------------------------");
		
		//再次獲取user物件
		User user2 = (User) session.get(User.class,1);
		//將user2的資訊打印出來
		System.out.println(user2);
		
		//事務提交
		transaction.commit();
	}

}

控制檯列印的資訊:

通過控制檯列印的資訊可以看到在第一次查詢使用者小明的資訊的時候一級快取中沒有小明的資料,所以傳送了sql語句到資料庫中查詢。而第二次再查詢小明資訊時一級快取中已經有了小明的資訊,所以直接拿過來用,並沒有再次到資料庫中查詢。

一級快取測試2:

    @Test
	void test2() {
		//獲取session
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		//開啟事務
		Transaction transaction = session.beginTransaction();
		
		User user=new User();
		user.setUserName("小花");
		user.setAge(19);
		user.setSex("女");
		
        //儲存物件
		session.save(user);
		
		//事務不提交
    	//transaction.commit();
	}

控制檯資訊:

此時可以看到控制檯已經打印出sql語句,但是因為事務沒提交,也沒呼叫session.flush()方法。所以到資料庫中檢視使用者表可以發現小花這條資料並沒有插入。

將程式碼修改一下,呼叫transaction.commit();提交事務。執行可以看到控制檯列印的資訊還是跟上面一樣,但是這時候開啟資料庫使用者表就可以看到小花這條資料已經插入到資料庫了。

延遲載入get()與load()區別:

1、get():

a、get的載入很積極,呼叫立即傳送sql語句。

b、返回的是個正式的物件。

c、如查詢到一個不存在的資料返回的時null。

2、load():

a、懶載入

b、返回的是個代理物件,這個代理物件中只有id有值,其他屬性都是空值

c、查詢一個不存在的資料丟擲異常

get()測試:

@Test
	void test3() {
		//獲取session
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		//開啟事務
		Transaction transaction = session.beginTransaction();
		
		User user = (User) session.get(User.class, 1);
		
		//事務提交
		transaction.commit();
	}

控制檯資訊:

測試程式碼中並沒有使用到user物件,但是hibernate還是傳送了sql。

接著測試通過get獲取一個數據庫中不存在的物件,程式碼與上面的程式碼一致,因為目前資料庫中不存在id為4的使用者,所以將

User user = (User) session.get(User.class, 1);該為User user = (User) session.get(User.class, 4);接著列印user。

通過控制檯可以看到返回的是一個null;

load()測試:

@Test
	void test4() {
		//獲取session
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		//開啟事務
		Transaction transaction = session.beginTransaction();

		User user = (User) session.load(User.class, 1);
		//先不列印user
//		System.out.println(user);
		
		//事務提交
		transaction.commit();
	}

先不列印user物件,執行觀察控制檯可以發現並沒有傳送sql語句查詢資料。接著將程式碼改一下列印user物件。再觀察控制檯。

可以發現當用到該物件時才會真正傳送sql去查詢,所以稱為懶載入。

接著測試用load()查詢一個不存在的資料。

@Test
	void test5() {
		//獲取session
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		//開啟事務
		Transaction transaction = session.beginTransaction();

		//因為id為4的使用者資料庫中不存在所以用4測試
		User user = (User) session.load(User.class, 4);
		//列印user  因為只有使用到了user物件才會載入
		System.out.println(user);
		
		//事務提交
		transaction.commit();
	}

觀察單元測試:

可以發現通過load方式查詢不存在的資料會出物件找不到的異常。

補充:load()的懶載入是可以更改為立即載入的,只需要再對映檔案中的class標籤內將lazy屬性設為false就可以變成立即載入。