※一級快取
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,畫面還是一片空白,不過反正註解都說是效率低的,就不要用就好了
找到這篇文章,已後有時間再測
沒有留言:
張貼留言