一 事務是什麼
1 事務的概念
1.1 爲什麼需要事務
在我們日常系統開發當中,我們是不是不可避免的要對一些數據資源 進行訪問,但是我們怎麼來保證我們對數據資源的訪問不會破壞數據資源的完整性呢?這個時候就需要事務了,正是引入了事務的概念,我們平時對數據資源進行操作的時候纔不會破壞數據資源的完整性或者說是不變量約束 。1.2 何爲事務
前面從爲什麼需要事務的角度,我們意識到了事務其實就是用來保護系 統處於一致性性狀態的一種措施。也可以說是一系列原子操作 的集合。2 事務的特徵
前面從事務目的的角度說明了事務到底是什麼,那麼事務又是達到保證數據資源完整性的目的的呢?這需要我們來了解一下事務的特徵,事務一共有四個特性 (ACID) ,分別是原子性( Atomicity), 一致性( Consistency), 隔離性( Isolation), 持久性( Durability).2.1 原子性
何爲原子性?之前說了事務需要保證數據資源的完整性,那麼我們就需要控制對數據資源的訪問,使得對數據資源進行訪問的操作要麼全部成功,否則只要一個操作失敗,那麼全部失敗(雖然有點極端 ^_^ ,但是很必要),這樣數據資源就不會因爲一部分操作成功,但是一部分操作失敗而引起系統不一致。2.2 一致性
何爲一致性呢?一致性就是說,當我們在對數據資源的一次訪問過程中,在訪問之前和訪問之後,數據資源的狀態都要處於一種完整的,滿足不變量約束的狀態。(比如銀行轉賬,當從賬戶 A 轉賬到賬戶 B 後,賬戶 A 和賬戶B 的金額總和是不變的,這就是一種不變量約束)。其實一致性也說出了事務的心聲,這也正是事務的目的,但是要想實現此目的,事務必須滿足其它的三條特徵,原子性,隔離性,持久性是一致性的必要條件。
2.3 隔離性
何爲隔離性?隔離性主要是考慮到了系統的併發操作,但系統對數據資 源進行訪問的時候,可能同時有好多個併發操作同時進行,這樣爲了保證系 統的一致性,事務必須具有一定的隔離性,使得併發執行的一些列操作互相 不要產生干擾。總之,事務的隔離性,主要是爲了保證在多線程環境下,數據資源的一 致性。
2.4 持久性
何爲持久性?持久性就是指在事務結束的時候,事務的結果應該被持久 的保存下來,此特徵也是爲一致性來服務的,試想一下,假如事務成功了, 但是此時突然斷電或者其它的故障,那麼此時事務的結果還是應該要保存下 來,不然系統的不變量約束就遭到了破壞。以上是事務的四特徵,下面主要來說說事務的隔離性問題,對於事務的隔離性問題, ANSI 標準規定了四個隔離級別,如下 :
3 事務的隔離級別
在說隔離級別以前,我們先來明確兩個問題,讀取事務和寫事務,讀取事務只是對數據庫進行讀操作,不會引起數據庫狀態變化,而寫事務要對數據庫進行更新。下面就以讀事務和寫事務來加以描述:3.1 讀取未提交( Read uncommited)
讀取未提交隔離級別是最低的一種隔離級別,其中讀事務不會阻塞任 何事務,寫事務阻塞寫事務,但是不阻塞讀事務,正是因爲寫事務不阻塞讀 事務,所以就造成讀取事務讀到的數據可能是髒的,這也就是著名的“髒讀 問題”,同時因爲讀事務沒有阻塞寫事務,所以在讀事務中的兩次讀取操作 可能讀到不同的數據,這也就造成了著名的“不可重複讀問題”,同理此種 情況下也存在“幻影讀”問題。3.2 讀取已提交( Read commited)
讀取已提交隔離級別中,讀事務不會阻塞任何事務,但是寫事務會阻塞 讀事務和其它寫事務,此時因爲寫事務會阻塞讀事務,所以不會出現“髒讀” 問題,但是因爲此時讀事務還是不阻塞寫事務,所以“不可重複讀”問題還 會出現,同時“幻影讀”問題還是會出現。3.3 可重複讀( Repeatable Read)
可重複讀隔離級別中,讀事務會阻塞寫事務,不阻塞讀事務,寫事務 會阻塞寫事務和讀事務,因爲此時讀事務阻塞了寫事務,所以避免了“不可 重複讀”的問題,但是此時讀事務並沒有阻塞對數據庫的插入操作,所以此 時“幻影讀”問題照樣存在。3.4 序列化 (Serializable)
Serializable 隔離級別是最嚴格一種隔離級別,數據庫系統會保證執行 此種隔離級別事務的效果和順序執行的效果一致。不過在日常的開發過程種 很少使用此種隔離級別,因爲它嚴重影響了系統的性能。以上就是事務的四種隔離級別,但是實際的開發當中,我們還是需要注意以下幾個問題:
1 並不是所有的數據庫都支持以上的四種隔離級別,具體的數據庫支持的隔離級別可參考相應的數據庫文檔。
2 在實際的開發當中,我們經常還會遇到一個問題就是如何在事務隔離級別和系統的併發性方面取得一個折中,如果採用 serializable 隔離級別,這樣數據庫就做好了併發控制,但是系統性能非常差,此時我們一般採用讀取已提交的隔離級別,然後再結合以下幾種併發控制的鎖定策略:
* 樂觀所
* 悲觀鎖
* 樂觀離線鎖
* 悲觀離線鎖
此時其實併發是由應用程序來控制的,而事務的隔離由數據庫系統來管理。
二 事務模型解析
首先事務模型分爲好幾種比如平面事務,嵌套事務等,平面事務是一個完整的不能再進行嵌套的事務,而嵌套型事務容許事務進行嵌套,事務嵌套子事務,這樣主事務可以對嵌套子事務進行重試,這樣增加了事務成功的總體的成功率,嵌套式事務最典型的例子就是訂票。比如某人要去旅行,需要路徑 A,B,C , D 四個不同的地方, A 到 B 需要訂火車票, B 到 C 需要訂機票, C 到 D 需要訂船票,那麼如果採用平面事務,只要 A,B,C,D 任意一段路程訂票失敗那麼就訂票失敗了,這樣明顯成功率比較低,這種情況下可以採用嵌套型事務來避免平面性事務的剛性失敗的缺點。上面說了常見的事務模型的類型,下面主要說一下目前 JAVAEE 應用中,我們常見的事務,本地事務或者 resource-local 事務和全局事務或者說 JTA 事務,需要聲明的是 resource-local 和 jta 事務都屬於前面說的平面事務模型。在具體說這兩種不同類型事務之前,首先我們來明確幾個事務管理會涉及到的幾個參與者:
1 資源管理器( Resource Manager) :資源管理器一般是數據庫管理系統,也可以是消息隊列,遺留系統等。
2 分佈式事務協調者( Distributed Transaction Coordinator,DTC) 【 1 】:此功能一般是有我們所用的 JavaEE 應用服務器實現,比如 jboss,websphere,weblogic 等。這個角色只有在 JTA 事務中才會存在。
3 事務管理器 (Transaction manager) :每一個事務管理器都與相應的資源管理器所關聯,它負責對分佈式事務進行提交或者回滾。
4 應用程序( Application)
以上四者的關係可以用以下的圖形來形象的表述:
在日常的系統開發中,我們一般都會使用數據資源(比如數據庫)來對系統的狀態進行保存,那麼我們根據系統涉及的數據資源的多少,將事務分爲 RESOURCE-LOCAL 事務或者 JTA 全局分佈式事務。
1 RESOURCE-LOCAL 事務
RESOURCE-LOCAL 事務是指只有一個資源管理( RM) 的事務,比如 我們系統中只涉及到一個數據庫,更準確點說應該是事務操作都是對同一個 數據庫進行操作。
此時事務協調着和事務管理器的作用就有底層的資源管理器來實現了。比如目前我們在採用 spring 來管理事務的時候,其實 spring 並沒有事務功能,它僅僅是封裝了底層數據庫的事務操作而已。
2 全局事務或者 JTA 事務
全局事務是涉及多個資源管理器,此時需要引入事務協調者來進行調節,此時就需要兩階段提交協議2PC ( two phase commit) ,下面簡要說一下兩階段提交協議。
第一階段:事務協調者發送“準備提交”消息給事務所涉及的所有的事務管理器,然後事務管理器又分送此消息給相應的資源管理器,然後事務管理器又將資源管理的響應情況告訴分佈式事務協調者( DTC). 只有此階段順利完成後(既所有的資源管理器都同意提交事務),纔會進入第二階段。
第二階段:當第一個階段順利完成後,事務協調者告訴事務管理器去提交事務