1. 程式人生 > >Hibernate的事務處理機制和flush方法的用法

Hibernate的事務處理機制和flush方法的用法

注:轉自http://www.cnblogs.com/wangkai1990/p/5704529.html。

首先來看下,session的生命週期

Hibernate中java物件的三種狀態:

1、臨時狀態(transient):用new語句建立,還沒有被持久化,不處於Session的快取中。 

2、持久化狀態(persistent):已使用save()或者saveOrUpdate()方法,處於Session的快取中和資料庫表中,生成了自己的Oid標識。 

3、遊離狀態(detached):被持久化,已使用evict(Object),session.close()或者使用clear()清除快取,不再處於Session的快取中或不存在資料庫表中,但是依然是存在自己的OId標識。 

物件的狀態轉換

                                                         

從上面的圖中我們可以很清楚的明白一個java物件在session中三種狀態的轉換,

然後在來看看session快取在什麼時候會被清除:

1.當應用程式呼叫org.hibernate.Transaction的commit()方法的時候,commit()方法先清理快取,然後再向資料庫提交事務。 

2.當應用程式顯式呼叫Session的flush()方法的時候,其實這個方法我們幾乎很少用到,因為我們一般都是在完成一個事務才去清理快取,提交資料更改,這樣我們直接提交事務就可以。

clear()和evict(Object)的區別:

從引數就可以看出,clear()是會清除整個session中的快取,evict(Object)是將一個物件從session快取中清除;

其實在session持久化操作和資料庫中之間還有一層物件緩衝區(entityEntries)

              

Commit():此方法在執行後會更新物件在物件快取區中的existsInDatabase=true;

Flush():會按save,update,delete順序執行,把快取中的資料flush入資料庫中,並清空快取區;

下面幾個例子可以充分說明我們異常丟擲的情況:

SessionFactory sf = newConfiguration().configure().buildSessionFactory() ;
Session s = sf.openSession();
Person person = new Person();

Transaction tran =s.beginTransaction(); (1)
s.save(person); (2)(此處同樣可以為updatedelete)
s.evict(person); (3)
tran.commit(); (4)
s.close();(5)

看上面的程式碼,再參照下我們的示例圖和commit()方法,就可以很明顯的發現程式碼問題的所在,在第四步evict()方法將cat物件從物件快取區清除,當我們執行commit()方法後,更新物件在快取區中狀態的時候,由於已被清除,就會出現上述斷言的異常;

Person person1 = new Person();
person1.setName(“tom”);
s.save(person1);

person1.setName(“mary”);
s.update(person1);

Person person2 = new Person();
person2.setName(“tom”);
s.save(person2);

s.flush();

其實在這裡我們看這個程式碼的時候感覺是沒問題 ,在這裡我們可以參考下剛提到的flush()方法,此方法會按save,update,delete的順序進行提交事務,所以在這裡會丟擲主鍵衝突的異常,解決的辦法是在update()操作後面也加入flush();

總的來說,由於flush()的特殊處理機制,雖然不建議使用此方法,但是在一些複雜的事務處理過程中,加入此方法雖然會破壞事務的一個提交的完整性,但是可以規避一些不可預見的異常情況!