hibernate 事務理解

簡介:

Hibernate自己並不具有事務管理能力 。在事務管理層,
Hibernate將其委託給底層的JDBC或者JTA ,以實現事務管理和調度功能。
Hibernate的默認事務處理機制基於JDBC Transaction。java

 

JTA 提供了跨Session 的事務管理能力。這一點是與JDBC Transaction 最大的
差別。
JDBC事務由Connnection管理,也就是說,事務管理其實是在JDBC Connection
中實現。事務週期限於Connection的生命週期之類。一樣,對於基於JDBC Transaction
的Hibernate 事務管理機制而言,事務管理在Session 所依託的JDBC Connection
中實現,事務週期限於Session的生命週期。
JTA 事務管理則由 JTA 容器實現,JTA 容器對當前加入事務的衆多Connection 進
行調度,實現其事務性要求。JTA的事務週期可橫跨多個JDBC Connection生命週期。
一樣對於基於JTA事務的Hibernate而言,JTA事務橫跨可橫跨多個Session。數據庫

 

9.3 Hibernate的事務管理 session

事務(Transaction)是工做中的基本邏輯單位,能夠用於確保數據庫可以被正確修改,避免數據只修改 了一部分而致使數據不完整,或者在修改時受到用戶干擾。做爲一名軟件設計師,必須瞭解事務併合理利用,以確保數據庫保存正確、完整的數據。數據庫向用戶提 供保存當前程序狀態的方法,叫事務提交(commit);當事務執行過程當中,使數據庫忽略當前的狀態並回到前面保存的狀態的方法叫事務回滾 (rollback)。數據結構

9.3.1 事務的特性

事務具有原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和持久性(Durability)4個屬性,簡稱ACID。下面對這4個特性分別進行說明。併發

l         原子性:將事務中所作的操做捆綁成一個原子單元,即對於事務所進行的數據修改等操做,要麼所有執行,要麼所有不執行。分佈式

l         一致性:事務在完成時,必須使全部的數據都保持一致狀態,並且在相關數據中,全部規則都必須應用於事務的修改,以保持全部數據的完整性。事務結束時,全部的內部數據結構都應該是正確的。性能

l         隔離性:由併發事務所作的修改必須與任何其餘事務所作的修改相隔離。事務查看數據時數據所處的狀態,要麼是被另外一併發事務修改以前的狀態,要麼是被另外一併 發事務修改以後的狀態,即事務不會查看由另外一個併發事務正在修改的數據。這種隔離方式也叫可串行性。spa

l         持久性:事務完成以後,它對系統的影響是永久的,即便出現系統故障也是如此。hibernate

9.3.2 事務隔離

事務隔離意味着對於某一個正在運行的事務來講,好像系統中只有這一個事務,其餘併發的事務都不存在同樣。在大部分狀況下,不多使用徹底隔離的事務。但不徹底隔離的事務會帶來以下一些問題。設計

l         更新丟失(Lost Update):兩個事務都企圖去更新一行數據,致使事務拋出異常退出,兩個事務的更新都白費了。

l         髒數據(Dirty Read):若是第二個應用程序使用了第一個應用程序修改過的數據,而這個數據處於未提交狀態,這時就會發生髒讀。第一個應用程序隨後可能會請求回滾被修改的數據,從而致使第二個事務使用的數據被損壞,即所謂的「變髒」。

l         不可重讀(Unrepeatable Read):一個事務兩次讀同一行數據,但是這兩次讀到的數據不同,就叫不可重讀。若是一個事務在提交數據以前,另外一個事務能夠修改和刪除這些數據,就會發生不可重讀。

l         幻讀(Phantom Read):一個事務執行了兩次查詢,發現第二次查詢結果比第一次查詢多出了一行,這多是由於另外一個事務在這兩次查詢之間插入了新行。

針對由事務的不徹底隔離所引發的上述問題,提出了一些隔離級別,用來防範這些問題。

l         讀操做未提交(Read Uncommitted):說明一個事務在提交前,其變化對於其餘事務來講是可見的。這樣髒讀、不可重讀和幻讀都是容許的。當一個事務已經寫入一行數據但 未提交,其餘事務都不能再寫入此行數據;可是,任何事務均可以讀任何數據。這個隔離級別使用排寫鎖實現。

l         讀操做已提交(Read Committed):讀取未提交的數據是不容許的,它使用臨時的共讀鎖和排寫鎖實現。這種隔離級別不容許髒讀,但不可重讀和幻讀是容許的。

l         可重讀(Repeatable Read):說明事務保證可以再次讀取相同的數據而不會失敗。此隔離級別不容許髒讀和不可重讀,但幻讀會出現。

l         可串行化(Serializable):提供最嚴格的事務隔離。這個隔離級別不容許事務並行執行,只容許串行執行。這樣,髒讀、不可重讀或幻讀均可發生。

事務隔離與隔離級別的關係如表9-2所示。

表9-2 事務隔離與隔離級別的關係

隔 離 級 別

髒讀(Dirty Read)

不可重讀(Unrepeatable read)

幻讀(Phantom Read)

讀操做未提交(Read Uncommitted)

可能

可能

可能

讀操做已提交(Read Committed)

不可能

可能

可能

可重讀(Repeatable Read)

不可能

不可能

可能

可串行化(Serializable)

不可能

不可能

不可能

在一個實際應用中,開發者常常不能肯定使用什麼樣的隔離級別。太嚴厲的級別將下降併發事務的性能,可是不足夠的隔離級別又會產生一些小的Bug,而這些Bug只會在系統重負荷(也就是併發嚴重時)的狀況下才會出現。

通常來講,讀操做未提交(Read Uncommitted)是很危險的。一個事務的回滾或失敗都會影響到另外一個並行的事務,或者說在內存中留下和數據庫中不一致的數據。這些數據可能會被另外一個事務讀取並提交到數據庫中。這是徹底不容許的。

另外,大部分程序並不須要可串行化隔離(Serializable Isolation)。雖然,它不容許幻讀,但通常來講,幻讀並非一個大問題。可串行化隔離須要很大的系統開支,不多有人在實際開發中使用這種事務隔離模式。

如今留下來的可選的隔離級別是讀操做已提交(Read Committed)和可重讀(Repeatable Read)。Hibernate能夠很好地支持可重讀(Repeatable Read)隔離級別。

9.3.3 在Hibernate配置文件中設置隔離級別

JDBC鏈接數據庫使用的是默認隔離級別,即讀操做已提交(Read Committed)和可重讀(Repeatable Read)。在Hibernate的配置文件hibernate.properties中,能夠修改隔離級別:

#hibernate.connection.isolation 4

在上一行代碼中,Hibernate事務的隔離級別是4,這是什麼意思呢?級別的數字意義以下。

l         1:讀操做未提交(Read Uncommitted)

l         2:讀操做已提交(Read Committed)

l         4:可重讀(Repeatable Read)

l         8:可串行化(Serializable)

所以,數字4表示「可重讀」隔離級別。若是要使以上語句有效,應把此語句行前的註釋符「#」去掉:

hibernate.connection.isolation 4

也能夠在配置文件hibernate.cfg.xml中加入如下代碼:

<session-factory>

…..

//把隔離級別設置爲4

<property name=」 hibernate.connection.isolation」>4</property>

……

</session-factory>

在開始一個事務以前,Hibernate從配置文件中得到隔離級別的值。

9.3.4 在Hibernate中使用JDBC事務

Hibernate對JDBC進行了輕量級的封裝,它自己在設計時並不具有事務處理功能。Hibernate 將底層的JDBCTransaction或JTATransaction進行了封裝,再在外面套上Transaction和Session的外殼,實際上是 經過委託底層的JDBC或JTA來實現事務的處理功能的。

要在Hibernate中使用事務,能夠在它的配置文件中指定使用JDBCTransaction或者JTATransaction。在hibernate.properties中,查找「transaction.factory_class」關鍵字,獲得如下配置:

# hibernate.transaction.factory_class org.hibernate.transaction.JTATransactionFactory

# hibernate.transaction.factory_class org.hibernate.transaction.JDBCTransactionFactory

Hibernate的事務工廠類能夠設置成JDBCTransactionFactory或者JTATransactionFactory。若是不進行配置,Hibernate就會認爲系統使用的事務是JDBC事務。

在JDBC的提交模式(commit mode)中,若是數據庫鏈接是自動提交模式(auto commit mode),那麼在每一條SQL語句執行後事務都將被提交,提交後若是還有任務,那麼一個新的事務又開始了。

Hibernate在Session控制下,在取得數據庫鏈接後,就馬上取消自動提交模式,即 Hibernate在一個執行Session的beginTransaction()方法後,就自動調用JDBC層的 setAutoCommit(false)。若是想本身提供數據庫鏈接並使用本身的SQL語句,爲了實現事務,那麼一開始就要把自動提交關掉 (setAutoCommit(false)),並在事務結束時提交事務。

使用JDBC事務是進行事務管理最簡單的實現方式,Hibernate對於JDBC事務的封裝也很簡單。下面是一個在Hibernate中使用JDBC事務的例子:

try {

Session session = HibernateUtil.currentSession();

Transaction tx = session.beginTransaction(); //在默認狀況下,開啓一個JDBC事物

for(int i=0; i<10; i++) {

    Student stu = new Student();

    stu.setName("Student" + i);

    session.save(stu);

}

    tx.commit(); //提交事務

    session.close();

} catch(Exception e) {…

tx.rollback();   //事務回滾

}

9.3.5 在Hibernate中使用JTA事務

JTA(Java Transaction API)是事務服務的J2EE解決方案。本質上,它是描述事務接口的J2EE模型的一部分,開發人員直接使用該接口或者經過J2EE容器使用該接口來確保業務邏輯可以可靠地運行。

JTA有3個接口,它們分別是UserTransaction接口、TransactionManager接 口和Transaction接口。這些接口共享公共的事物操做,例如commit()和rollback(),但也包含特殊的事務操做,例如 suspend()、resume()和enlist(),它們只出如今特定的接口上,以便在實現中容許必定程度的訪問控制。

在一個具備多個數據庫的系統中,可能一個程序會調用幾個數據庫中的數據,須要一種分佈式事務,或者準備用JTA來管理跨 Session的長事務,那麼就須要使用JTA事務。下面介紹如何在Hibernate的配置文件中配置JTA事務。在 hibernate.properties文件中設置以下(把JTATransactionFactory所在的配置行的註釋符「#」取消掉):

hibernate.transaction.factory_class org.hibernate.transaction.JTATransactionFactory

# hibernate.transaction.factory_class org.hibernate.transaction.JDBCTransactionFactory

或者在hibernate.cfg.xml文件中配置以下:

<session-factory>

…..

<property name=」 hibernate.transaction.factory_class」>

org.hibernate.transaction.JTATransactionFactory

</property>

……

</session-factory>

下面是一個應用JTA事務的例子:

javax.transaction.UserTransaction tx = null;

tx = new initialContext().lookup(」 javax.transaction.UserTransaction 」) ;

tx.begin();

Session s1 = sf.openSession();

……

s1.flush(); s1.close();

Session s2 = sf.openSession();

……

s2.flush(); s2.close();

tx.commit();

相關文章
相關標籤/搜索