http://blog.csdn.net/wkcgy/article/details/6192839
Hibernate的clear(),flush(),evict()方法詳解
分類: Hibernate SSH 2011-02-18 11:02 944人閱讀 評論(1) 收藏 舉報
1.Clear 方法
無論是Load 還是 Get 都會首先查找緩存(一級緩存) 如果沒有,纔會去數據庫查找,調用Clear() 方法,可以強制清除Session緩存。
例:
[c-sharp] view plaincopyprint?
public void testClear(){
Session session = HibernateUitl.getSessionFactory().getCurrentSession();
session.beginTransaction();
Teacher t = (Teacher) session.get(Teacher.class, 3);
System.out.println(t.getName());
Teacher t2 = (Teacher) session.get(Teacher.class, 3);
System.out.println(t2.getName());
session.getTransaction().commit();
}
這裏雖然用了2 個 get 方法( get 方法會立即執行 sql 語句),但因爲第一次執行了會緩存一個 ID 爲 3 的實體,所以雖然有 2 個 get 方法只執行一次 SQL 語句。
public void testClear(){
Session session = HibernateUitl.getSessionFactory().getCurrentSession();
session.beginTransaction();
Teacher t = (Teacher) session.get(Teacher.class, 3);
System.out.println(t.getName());
session.clear();//這裏不clear只會執行一次sql語句,有clear會執行2次
Teacher t2 = (Teacher) session.get(Teacher.class, 3);
System.out.println(t2.getName());
session.getTransaction().commit();
}
這裏在第2 次 get 前執行 session.clear(), 我們把 hibernate show_sql 出來,它就會執行 2 次 sql 語句了。 所以session.clear() 會清除緩存。
2.Flush方法
可以強制進行從內存到數據庫的同步。
例:
/**
* flush 強制與數據庫同步
*/
public void testFlush(){
Session session = HibernateUitl.getSessionFactory().getCurrentSession();
session.beginTransaction();
Teacher t = (Teacher) session.get(Teacher.class, 3);
t.setName("yyy");
t.setName("yyyyy");
session.getTransaction().commit();
}
看這段代碼,我們setName() 2 次, 但程序只會更改數據庫一次,在 commit 時。
/**
* flush 強制與數據庫同步
*/
public void testFlush(){
Session session = HibernateUitl.getSessionFactory().getCurrentSession();
session.beginTransaction();
Teacher t = (Teacher) session.get(Teacher.class, 3);
t.setName("yyy");
session.flush();//有flush會執行2次UPDAE,沒有會只執行一次
t.setName("yyyyy");
session.getTransaction().commit();
}
我們在第2 次 setName ()時 執行 session.flush().
再看hibernate 執行的 sql 語句
[c-sharp] view plaincopyprint?
Hibernate:
update
Teacher
set
birthday=?,
name=?,
title=?
where
id=?
Hibernate:
update
Teacher
set
birthday=?,
name=?,
title=?
where
id=?
執行了2 次 Update
所以看出來flush 方法會強制與數據庫同步。
Flush方法是可以設置的,也就是 fulsh 什麼時候執行是可以設置的
在session.beginTransaction 前設置 FlushMode
session.setFlushMode(FlushMode.Always|AUTO|COMMIT|NEVER|MANUAL)
FlushMode有 5 個值可選
Always:任何代碼都會 Flush
AUTO:默認方式 – 自動
Commit:COMMIT時
Never:始終不
MANUAL:手動方式
設置FlushMode 有個好處是可以節省開銷,比如默認 session 只做查詢時,就可以不讓他與數據庫同步了。
session.evict(obj) :會把指定的緩衝對象進行清除。
session.clear() :把緩衝區內的全部對象清除,但不包括操作中的對象。
Hibernate 執行的順序如下:
(1) 生成一個事務的對象,並標記當前的 Session 處於事務狀態(注:此時並未啓動數據庫級事務)。
(2) 應用使用 s.save 保存對象,這個時候 Session 將這個對象放入 entityEntries ,用來標記對象已經和當前的會話建立了關聯,由於應用對對象做了保存的操作, Session 還要在 insertions 中登記應用的這個插入行爲(行爲包括:對象引用、對象 id 、 Session 、持久化處理類)。
(3)s.evict 將對象從 s 會話中拆離,這時 s 會從 entityEntries 中將這個對象移出。
(4) 事務提交,需要將所有緩存 flush 入數據庫, Session 啓動一個事務,並按照 insert,update,……,delete 的順序提交所有之前登記的操作(注意:所有 insert 執行完畢後纔會執行 update ,這裏的特殊處理也可能會將你的程序搞得一團糟,如需要控制操作的執行順序,要善於使用 flush ),現在對象不在 entityEntries 中,但在執行 insert 的行爲時只需要訪問 insertions 就足夠了,所以此時不會有任何的異常。異常出現在插入後通知 Session 該對象已經插入完畢這個步驟上,這個步驟中需要將 entityEntries 中對象的 existsInDatabase 標誌置爲 true ,由於對象並不存在於 entityEntries 中,此時 Hibernate 就認爲 insertions 和 entityEntries 可能因爲線程安全的問題產生了不同步(也不知道 Hibernate 的開發者是否考慮到例子中的處理方式,如果沒有的話,這也許算是一個 bug 吧),於是一個 net.sf.hibernate.AssertionFailure 就被拋出,程序終止。
一般我們會錯誤的認爲 s.save 會立即執行,而將對象過早的與 Session 拆離,造成了 Session 的 insertions 和 entityEntries 中內容的不同步。所以我們在做此類操作時一定要清楚 Hibernate 什麼時候會將數據 flush 入數據庫,在未 flush 之前不要將已進行操作的對象從 Session 上拆離。解決辦法是在 save 之後,添加 session.flush 。