Hibernate(十六)數據庫事務與隔離級別



           數據庫事務: 事務是指一組相互依賴的操作行爲,如銀行交易、股票交易或網上購物。事務的成功取決於這些相互依賴的操作行爲是否都能執行成功,只要有一個操作行爲失敗, 就意味着整個事務失敗。關於事務的一個經典例子就是:A到銀行辦理轉賬事務,把100元錢轉到B的賬號上,這個事務包含以下操作行爲: 

(1)從A的賬戶上減去100元。 

(2)往B的賬戶上增加100元。

      顯然,以上兩個操作必須作爲一個不可分割的工作單元。假如僅僅第一步操作執行成功,使得Tom的賬戶上扣除了100元,但是第二步操作執行失敗,Jack 的賬戶上沒有增加100元,那麼整個事務失敗。 數據庫事務是對現實生活中事務的模擬,它由一組在業務邏輯上相互依賴的SQL語句組成。 

 下面我們一起來看一下數據庫事務的生命週期:

                                             

這個數據庫事務的生命週期圖反應出數據庫事務的三個邊界:

1.事務的開始邊界。 

2.事務的正常結束邊界(COMMIT):提交事務,永久保存被事務更新後的數據庫狀態。 

3.事務的異常結束邊界(ROLLBACK):撤銷事務,使數據庫退回到執行事務前的初始狀態。 

其實每個數據庫連接都有個全局變量@@autocommit,表示當前的事務模式,它有兩個可選值: 0:表示手工提交模式。 1:默認值,表示自動提交模式 

在自動提交模式下,每個SQL語句都是一個獨立的事務。也就是說,每執行一條sql語句,數據庫都會自動提交這個事務,當我們用數據庫另一個客戶端去查詢的時候,我們可以看到這個新修改或插入的數據。在手工提交模式下,必須顯式指定事務開始邊界和結束邊界: 

–事務的開始邊界:begin 

–提交事務:commit 

–撤銷事務:rollback 



下面我們來看一下通過JDBC API是如何聲明事務邊界的:

Connection提供了以下用於控制事務的方法: 

1.setAutoCommit(boolean autoCommit):設置是否自動提交事務 

2.commit():提交事務 

3.rollback():撤銷事務 

下面我們看一下具體的應用示例:



try { 
con = java.sql.DriverManager.getConnection(dbUrl,dbUser,dbPwd); 
//設置手工提交事務模式 
con.setAutoCommit(false); 
stmt = con.createStatement(); 
//數據庫更新操作1 
stmt.executeUpdate("update ACCOUNTS set BALANCE=900 where ID=1 "); 
//數據庫更新操作2 
stmt.executeUpdate("update ACCOUNTS set BALANCE=1000 where ID=2 "); 
con.commit(); //提交事務 
}catch(Exception e) { 
try{ 
con.rollback(); //操作不成功則撤銷事務 
}catch(Exception ex){ 
//處理異常 
…… 
} 
//處理異常 
…… 
}finally{…}





       看到上邊的示例我們可以看出,其實hibernate事務邊界就是模仿者JDBC的事務邊界來的,其實在hibernate底層的事務管理就是利用的JDBC的事務管理。我們來看一下hibernate事務邊界:

1.聲明事務的開始邊界: 

Transaction tx=session.beginTransaction(); 

2.提交事務: tx.commit(); 

3.撤銷事務: tx.rollback(); 

       我們在學習JDBC數據庫事務管理的時候,重點也是難點的學習了jdbc多個事務併發問題。既然hibernate底層是用JDBC事務管理實現的,那麼它也一定存在着多個事務併發的問題。下面我們就具體來看一下:hibernate多個事務併發的併發問題:

第一類丟失更新:撤銷一個事務時,把其他事務已提交的更新數據覆蓋。 

髒讀:一個事務讀到另一事務未提交的更新數據。 

虛讀:一個事務讀到另一事務已提交的新插入的數據。 

不可重複讀:一個事務讀到另一事務已提交的更新數據。 

第二類丟失更新:這是不可重複讀中的特例,一個事務覆蓋另一事務已提交的更新數據。 

下面我們就髒讀來舉一個示例:

                                            

取款事務在T5時刻把存款餘額改爲900元,支票轉賬事務在T6時刻查詢賬戶的存款餘 額爲900元,取款事務在T7時刻被撤銷,支票轉賬事務在T8時刻把存款餘額改爲1000元。 由於支票轉賬事務查詢到了取款事務未提交的更新數據,並且 在這個查詢結果的基礎上進行更新操作,如果取款事務最後被撤銷,會導致***損失100元。 

事務隔離級別

關於事務隔離級別,我們來看一下下面的兩個圖解:

                                  

                                    

由上圖可以看出:隔離級別越高,越能保證數據的完整性和一致性,但是對併發性能的影響 也越大。 對於多數應用程序,可以優先考慮把數據庫系統的隔離級別設爲Read Committed,它能夠避免髒讀,而且具有較好的併發性能。儘管它會 導致不可重複讀、虛讀和第二類丟失更新這些併發問題,在可能出現這類問題的個別場合,可以由應用程序採用悲觀鎖或樂觀鎖來控制。 

下面我們就具體來看一下hibernate怎麼來配置隔離級別:在Hibernate的配置文件中可以顯式的設置隔離級別。每一種隔離級別都對應一個整數: 

1:Read Uncommitted 

2:Read Committed 

4:Repeatable Read 

8:Serializable 

例如,以下代碼把hibernate.cfg.xml文件中的隔離級別設爲Read Committed: 

hibernate.connection.isolation=2 

對於從數據庫連接池中獲得的每個連接,Hibernate都會把它改爲使用Read Committed隔離級別。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章