在說Session緩存之前我們先修改一下我們的項(xiàng)目,在項(xiàng)目中添加兩個(gè)方法
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
我的這兩個(gè)方法是我使用ide生成的,我們使用單元測試測試某個(gè)方法的時(shí)候,junit會(huì)先幫我執(zhí) setup ()方法,當(dāng)單元測試結(jié)束后junit會(huì)為我們執(zhí)行tearDown()方法。當(dāng)然方法名無所為,只要符合規(guī)定就可以隨便寫,主要的是@Before與@After這兩個(gè)注解。我們將hibernateTest1()
方法中的代碼剪切出來最終改造成這個(gè)樣子
public class HibernateTest {
private Session session = null;
private Transaction transaction = null;
@Before
public void setUp() throws Exception {
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
SessionFactory sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
session = sessionFactory.openSession();
transaction = session.beginTransaction();
}
@After
public void tearDown() throws Exception {
transaction.commit();
session.close();
}
@Test
public void hibernateTest1(){
}
}
看明白了吧,在開始單元測試的時(shí)候幫我們獲取一個(gè)Session對象并且開啟一個(gè)事務(wù),結(jié)束單元測試的時(shí)候,幫我們提交事務(wù)和關(guān)閉Session。
獲取一條記錄
????還記得我們在數(shù)據(jù)庫中插入了一條 name字段值為張三的一條記錄吧?我們現(xiàn)在來從數(shù)據(jù)庫中取出來。哦,對了我忘了和大家說一下由于Mac電腦安裝oracle安裝比較麻煩,再者使用服務(wù)器還是有點(diǎn)不方便。以后我都會(huì)使用mysql社區(qū)版做演示。

可以看出跟我們的預(yù)期效果是一樣,發(fā)送了一條sql語句來查詢數(shù)據(jù),我們在使用get方法獲取一遍數(shù)據(jù)

????可以看出連續(xù)兩條打印結(jié)果,但是只發(fā)送了一條sql語句來做查詢。那么問題來了,為什么第一遍使用get方法獲取數(shù)據(jù)需要發(fā)送sql語句,而第二次使用get方法獲取數(shù)據(jù)則不需要發(fā)送sql語句了呢?
????這是因?yàn)?,你第一次使用get方法的時(shí)候session會(huì)將你的要查詢的數(shù)據(jù)拿出來返回給你之后,并且會(huì)在session緩存中保存一份,所以當(dāng)你在同一個(gè)session中查詢相同數(shù)據(jù)的時(shí)候,會(huì)先到自己的緩存中去找,如果有則返回給你,如果沒有就去二級緩存中找,如果在沒有數(shù)據(jù)彩繪發(fā)送sql語句從數(shù)據(jù)庫中查找。
操作session緩存
????flush:當(dāng)我們調(diào)用flush方法時(shí),會(huì)將我們的增刪改操作同步到數(shù)據(jù)庫中。
????reflesh:強(qiáng)制同步緩存中的一個(gè)對象,就是說我們獲取了數(shù)據(jù),當(dāng)我們過了一段時(shí)間要繼續(xù)使用此數(shù)據(jù)的時(shí)候,但是不確定別人是否修改了此數(shù)據(jù),所以使用此方法來重新獲取一遍。當(dāng)然我們也可以先使用evict 方法將對象從session緩存中移除,然后在使用????get 方法獲取。
????clear:清空緩存。
????evict:從session緩存中移除某個(gè)對象。
????commit和flush區(qū)別:flush執(zhí)行一系列sql語句,但不提交事務(wù);commit方法先調(diào)用flush方法,然后提交事務(wù)。
理論
????一級緩存生命周期很短與Session生命周期一致,所以一級緩存也叫Session緩存或事物級緩存。為什么也叫事務(wù)級緩存呢,是因?yàn)樵鰟h改方法需要事務(wù)來完成,每次執(zhí)行增刪改后都要commit,所以也叫事務(wù)級緩存。
????位于緩存中的對象處于持久化狀態(tài),它和表中的相關(guān)記錄對應(yīng),Session能夠在某些時(shí)間點(diǎn),按照緩存中持久話對象的屬性變化來同步數(shù)據(jù)庫中表的記錄,這一過程稱為清理緩存。也就是說當(dāng)我們使用get方法查詢出數(shù)據(jù)庫某條記錄的時(shí)候,這時(shí)對象就處于持久狀態(tài),例如:User user = session.get(User.class, 1);
我們從數(shù)據(jù)庫中查詢出主鍵為1的數(shù)據(jù),這個(gè)時(shí)候user對象就處于持久狀態(tài)。說白了就是通過session得到的對象都是持久狀態(tài)對象。
????當(dāng)我們修改了此對象的屬性值,在使用session的方法進(jìn)行提交和刷新緩存時(shí),就會(huì)將你修改過的對象屬性值同步到數(shù)據(jù)庫表中,在提交或刷新緩存時(shí)的過程稱為清理緩存。當(dāng)然清理緩存不只是提交和刷新緩存,還有別的方法。
一級緩存實(shí)現(xiàn)原理:
????session緩存是由它的實(shí)現(xiàn)類SessionImpl中定義的一些集合屬性構(gòu)成的,原理是保證有一個(gè)引用在關(guān)聯(lián)某個(gè)持久話對象,保持它的生命周期不會(huì)結(jié)束。 大家都知道java中有垃圾回收器也就是GC,如果我們長時(shí)間不使用某個(gè)對象,那么他會(huì)在一定時(shí)間內(nèi),被java的垃圾回收器從內(nèi)存中清理掉,所以hibernate為了防止通過session獲取的對象被清理掉,在session緩存中一直保持著此對象的引用,直到session被關(guān)閉。
一級緩存的作用
????減少數(shù)據(jù)庫訪問量,例如我們總是要獲取數(shù)據(jù),每次都要鏈接數(shù)據(jù)庫查詢,這樣大大降低了運(yùn)行效率,所以我們都會(huì)通過session緩存來獲取數(shù)據(jù)。
