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兩次幹嗎?
一級快取的記憶體結構:
原始碼:
記憶體結構圖: