1. 程式人生 > >Hibernate學習筆記(三) — Hibernate 的一級快取意義

Hibernate學習筆記(三) — Hibernate 的一級快取意義

什麼是快取?

快取說白了,就是應用程式向資料庫要資料,然後把一些資料,臨時的放在了記憶體的區域中,第二次再要資料的時候,直接從記憶體中拿即可。

快取需要解決的事情:

1.能把資料放入快取 2.能把資料從快取中取出來 3.如果快取中的資料發生變化,需要把資料同步到資料庫中

4.把資料庫中的資料同步到快取中 5.hits命中率低的物件應該及時從快取中移走

分散式快取:

為什麼會有分散式快取?

應用程式執行在伺服器上,併發訪問時,伺服器壓力過大,分散式快取就是來分擔伺服器壓力的。

分散式快取之間的資料是同步的。(比如購物車中的資料都是存在session中)一旦某個伺服器掛了,那麼操作的資料在其他的伺服器的快取中還可以繼續取出來。所以在Tomcat叢集的時候,session是先存在了分散式快取中,在 tomcat 內部集成了memory cache的分散式快取,就能自動的把 session 同步。


面試,叢集時解決 session 問題:就是利用分散式快取來處理,tomcat可以與memory cache無縫的整合,在tomcat中配置即可。程式設計師不需要任何干涉。

比較流行的快取

小型應用:oscache,ehcache

分散式:memory cache,redis,hbase

一、Hibernate的一級快取

Hibernate的一級快取,也稱為 session 級別的快取,其生命週期與 session 的生命週期保持一致

一級快取的位置


持久化狀態的物件,就是進入了一級快取中,換句話說,如果一個物件是一個持久化物件,那麼這個物件一定在一級快取中。

二、Session的操作:

session.get():可以把物件放入到一級快取中,也可以從一級快取中把物件提取出來(第一次呼叫放,以後取)

session.save():可以把一個物件放入到一級快取中

session.evit():可以把一個物件從快取中清空

session.update():可以把一個物件放入到一級快取中

session.clear():清空一級快取中所有的資料

session.close():一級快取的生命週期結束

測試:

private Session session;
	private Transaction transaction;
	
	@Before
	public void init(){
		session = HibernateUtils.openSession();
		transaction = session.beginTransaction();
	}
	
	@Test
	public void testGet(){
		User user = (User) session.get(User.class, 1);//發sql,把物件放入到一級快取中
		User user2 = (User) session.get(User.class, 1);//從一級快取中直接取,不發sql
		//hibernate提供一個統計機制。獲取快取中實體的個數
		int count = session.getStatistics().getEntityCount();
		System.out.println(count);//1,所以get方法把物件放入到快取
		transaction.commit();
		session.close();
	}
	
	
	@Test
	public void testSave(){
		User user = new User();
		user.setAge(250);
		user.setName("heh");
		session.save(user);
		int count = session.getStatistics().getEntityCount();
		System.out.println(count);//1,所以save方法把物件放入到快取
		transaction.commit();
		session.close();
	}
	
	@Test
	public void testEvict(){
		User user = (User) session.get(User.class, 1);
		session.evict(user);
		int count = session.getStatistics().getEntityCount();
		System.out.println(count);//0,evit方法把get放入到快取中的物件,清空了
		transaction.commit();
		session.close();
	}
	
	@Test
	public void testUpdate(){
		User user = (User) session.get(User.class, 1);
		session.evict(user);
		/**
		 * 此處注意,evict方法之後,執行update會發送sql,即使物件不做任何修改
		 * 此處,可以加深session.flush(),進行的對照副本的操作的理解
		 * 註釋掉evict,就不會發送update語句
		 */
		session.update(user);
		int count = session.getStatistics().getEntityCount();
		
		System.out.println(count);//1,update方法把物件放入到快取
		transaction.commit();
		session.close();
	}
	

	@Test
	public void testClear(){
		User user = (User) session.get(User.class, 1);
		session.clear();
		int count = session.getStatistics().getEntityCount();
		System.out.println(count);//0,清空所有
		transaction.commit();
		session.close();
	}

三、一級快取的真正意義:

從資料庫中取出一個班級的所有學生資訊,對學生資訊進行修改,所有改的操作,都只是針對一級快取中的資料,只有在 session 的 flush 後,才會與資料庫互動。所以不論改多少人的資訊,都只是 session.flush之後才會與資料庫互動一次。這樣就可以提供效率。

而不是get一次,傳送一次sql語句,再次get就不傳送sql語句,取資料get一次就行,get兩次幹嗎?


一級快取的記憶體結構

原始碼:



記憶體結構圖: