※一級快取
Session s1 = HibernateUtil2.getSession();
Session s2 = HibernateUtil2.getSession();
try {
Emp e1 = (Emp) s1.get(Emp.class, 7369);
System.out.println("first:" + e1.getEname());
Emp e2 = (Emp) s2.get(Emp.class, 7369);
System.out.println("second:" + e2.getEname());
} catch (Exception e) {
System.err.println("例外錯誤!");
e.printStackTrace();
} finally {
if(s1.isOpen()){
s1.close();
}
if(s2.isOpen()){
s2.close();
}
}
※以控制台出現訊息為標準,預設就有一級快取,因為只有Select一次
SessionFactory sf = HibernateUtil2.getSessionFactory();
Session s1 = sf.openSession();
Session s2 = sf.openSession();
Emp e1 = (Emp) s1.get(Emp.class, 7369);
System.out.println("first:" + e1.getEname());
Emp e2 = (Emp) s2.get(Emp.class, 7369);
System.out.println("second:" + e2.getEname());
※有快取是因為基於同一個Session,像上面的程式碼,有兩個Session,就沒有快取了,會輸出兩次Select
Session s = HibernateUtil2.getSession();
Emp emp = new Emp();
emp.setEmpno(7369);
emp.setEname("XXX");
s.update(emp);
s.beginTransaction().commit();
Emp e = (Emp) s.get(Emp.class, 7369);
System.out.println("xxx:" + e.getEname());
※update時也一樣有快取,此時控制台輸出update語句,但沒有Select,照樣查詢的到
※save和delete我試的結果,在控制台除了insert和delete語句外,還是有Select語句
※管理快取
尤於上面的程式碼會快取,但如果有100萬條或更多的記錄也把它快取下來,這樣子極有可能造成效能變低和OutOfMemoryException,記憶體爆了,所以有以下兩種方法來管理快取Session s = HibernateUtil2.getSession();
Emp emp = new Emp();
emp.setEmpno(7369);
emp.setEname("SMITH");
s.update(emp);
s.beginTransaction().commit();
s.clear();
Emp e = (Emp) s.get(Emp.class, 7369);
System.out.println("second:" + e.getEname());
※可以用clear清除全部快取,所以查詢有語句
Session s = HibernateUtil2.getSession();
// Emp e1 = (Emp) s.get(Emp.class, 7369);
// System.out.println("e1:" + e1.getEname());
Emp e1 = new Emp();
e1.setEmpno(7369);
e1.setEname("SMITH");
s.update(e1);
s.beginTransaction().commit();
Dept d1 = (Dept) s.get(Dept.class, 20);
System.out.println("d1:" + d1.getDname());
s.evict(e1);
Emp e2 = (Emp) s.get(Emp.class, 7369);
System.out.println("e2:" + e2.getEname());
Dept d2 = (Dept) s.get(Dept.class, 20);
System.out.println("d2:" + d2.getDname());
※如果只想清除某個物件的快取,就要用evict,像我是將e1的快取清除,所以控制台輸出update語句,然後輸出Select Dept的語句,但因為有evict(e1),所以Select Emp也輸出了
※如果有二級快取,就沒有效果了
※Session.flush()
Session s = HibernateUtil2.getSession();
Emp emp = new Emp();
emp.setEmpno(7369);
emp.setEname("SMITH");
s.update(emp);
s.flush();
// s.beginTransaction().commit();
※像上面的程式碼,因為commit註解掉,控制台理論上是空白的,但因為有flush(),所以會輸出語句,但因為沒commit(),所以資料庫沒作用
※用commit(),其實也會flush後再提交
※flush總共有五種模式,先看原始碼的註解怎麼說
/**
* The {@link Session} is never flushed unless {@link Session#flush}
* is explicitly called by the application. This mode is very
* efficient for read only transactions.
*
* @deprecated use {@link #MANUAL} instead.
*/
public static final FlushMode NEVER = new FlushMode( 0, "NEVER" );
/**
* The {@link Session} is only ever flushed when {@link Session#flush}
* is explicitly called by the application. This mode is very
* efficient for read only transactions.
*/
public static final FlushMode MANUAL = new FlushMode( 0, "MANUAL" );
/**
* The {@link Session} is flushed when {@link Transaction#commit}
* is called.
*/
public static final FlushMode COMMIT = new FlushMode(5, "COMMIT");
/**
* The {@link Session} is sometimes flushed before query execution
* in order to ensure that queries never return stale state. This
* is the default flush mode.
*/
public static final FlushMode AUTO = new FlushMode(10, "AUTO");
/**
* The {@link Session} is flushed before every query. This is
* almost always unnecessary and inefficient.
*/
public static final FlushMode ALWAYS = new FlushMode(20, "ALWAYS");
※NEVER:此模式不能flush,除非明確呼叫應用程式,在只有唯讀時,效能很高,此模式已廢棄了,要使用MANUAL代替
※MANUAL:當明確呼叫應用程式,此模式永遠flush,在唯讀時,效能很高
※COMMIT:當呼叫commit時,清除快取
※AUTO:此Session查詢執行之前有時會flush,以確保查詢不會返回已經失效的狀態,這是預設的選項
※ALWAYS:在所有查詢之前都會清除快取,這幾乎是不必要且效率低的
Session s = HibernateUtil2.getSession();
// 五種模式
s.setFlushMode(FlushMode.AUTO);
s.setFlushMode(FlushMode.ALWAYS);
s.setFlushMode(FlushMode.COMMIT);
s.setFlushMode(FlushMode.MANUAL);
s.setFlushMode(FlushMode.NEVER);
System.out.println("first");
Emp e1 = (Emp) s.load(Emp.class, 7369);
s.beginTransaction().commit();
System.out.println("second");
Emp e2 = (Emp) s.get(Emp.class, 7369);
s.beginTransaction().commit();
※整理如下:
.NEVER:等同MANUAL,因以廢棄,註解也要我們使用MANUAL
.MANUAL:不使用flush
.COMMIT:commit前flush
.AUTO:這個我不知如何試,註解也是說有時會,什麼是「有時會」並沒有說清楚
.ALWAYS:這個我試不出來,以上面的程式碼來說,我用load,畫面還是一片空白,不過反正註解都說是效率低的,就不要用就好了
找到這篇文章,已後有時間再測
沒有留言:
張貼留言