http://blog.csdn.net/tuolaji8/article/details/48549481
一、事務的4個基本特征
所謂事務是用戶定義的一個數據庫操作序列,這些操作要么全做要么全不做,是一個不可分割的工作單位。例如,在關系數據庫中,一個事務可以是一條SQL語句、一組SQL語句或整個程序。 事務ACID特性。 ACID就是:原子性(Atomicity )、一致性( Consistency )、隔離性或獨立性( Isolation)和持久性(Durabilily)。
事務和程序是兩個概念。一般地講,一個程序中包含多個事務。
事務的開始與結束可以由用戶顯式控制。如果用戶沒有顯式地定義事務,則由DBMS按缺省規定自動划分事
務。在SQL語言中,定義事務的語句有三條:
BEGIN TRANSACTION
COMMIT
ROLLBACK
同生共死。。
顯示事務被用begin transaction 與 end transaction 標識起來,其中的 update 與 delete 語句或者全部執行或者全部不執行。。 如:
begin transaction T1
update student
set name='Tank'
where id=2006010
delete from student
where id=2006011
commit
end transaction T1
簡單地說,事務是一種機制,用以維護數據庫的完整性。
其實現形式就是將普通的SQL語句嵌入到Begin Tran...Commit Tran 中(或完整形式 Begin Transaction...Commit Transaction),當然,必要時還可以使用RollBack Tran 回滾事務,即撤銷操作。
利用事務機制,對數據庫的操作要么全部執行,要么全部不執行,保證數據庫的一致性。需要使用事務的SQL語句通常是更新和刪除操作等。
1、原子性 (Atomicity )
原子性屬性用於標識事務是否完全地完成,一個事務的任何更新要在系統上完全完成,如果由於某種原因出錯,事務不能完成它的全部任務,系統將返回到事務開始前的狀態。
讓我們再看一下銀行轉帳的例子。如果在轉帳的過程中出現錯誤,整個事務將會回滾。只有當事務中的所有部分都成功執行了,才將事務寫入磁盤並使變化 永久化。為了提供回滾或者撤消未提交的變化的能力,許多數據源采用日志機制。例如,SQL Server使用一個預寫事務日志,在將數據應用於(或提交到)實際數據頁面前,先寫在事務日志上。但是,其他一些數據源不是關系型數據庫管理系統 (RDBMS),它們管理未提交事務的方式完全不同。只要事務回滾時,數據源可以撤消所有未提交的改變,那么這種技術應該可用於管理事務。
2、一致性( Consistency )
事務在系統完整性中實施一致性,這通過保證系統的任何事務最后都處於有效狀態來實現。如果事務成功地完成,那么系統中所有變化將正確地應用,系統處於有效狀態。如果在事務中出現錯誤,那么系統中的所有變化將自動地回滾,系統返回到原始狀態。因為事務開
始時系統處於一致狀態,所以現在系統仍然處於一致狀態。 再讓我們回頭看一下銀行轉帳的例子,在帳戶轉換和資金轉移前,帳戶處於有效狀態。如果事務成功地完成,並且提交事務,則帳戶處於新的有效的狀態。如果事務出錯,終止后,帳戶返回到原先的有效狀態。
記住,事務不負責實施數據完整性,而僅僅負責在事務提交或終止以后確保數據返回到一致狀態。理解數據完整性規則並寫代碼實現完整性的重任通常落在 開發者肩上,他們根據業務要求進行設計。 當許多用戶同時使用和修改同樣的數據時,事務必須保持其數據的完整性和一致性。因此我們進一步研究A C I D特性中的下一個特性:隔離性。
3、隔離性 ( Isolation)
在隔離狀態執行事務,使它們好像是系統在給定時間內執行的唯一操作。如果有兩個事務,運行在相同的時間內,執行相同的功能,事務的隔離性將確保每一事務在 系統中認為只有該事務在使用系統。 這種屬性有時稱為串行化,為了防止事務操作間的混淆,必須串行化或序列化請求,使得在同一時間僅有一個請求用於同一數據。重要的是,在隔離狀態執行事務, 系統的狀態有可能是不一致的,在結束事務前,應確保系統處於一致狀態。但是在每個單獨的事務中,系統的狀態可能會發生變化。如果事務不是在隔離狀態運行, 它就可能從系統中訪問數據,而系統可能處於不一致狀態。通過提供事務隔離,可以阻止這類事件的發生。在銀行的示例中,這意味着在這個系統內,其他過程和事 務在我們的事務完成前看不到我們的事務引起的任何變化,這對於終止的情況非常重要。如果有另一個過程根據帳戶余額進行相應處理,而它在我們的事務完成前就 能看到它造成的變化,那么這個過程的決策可能
建立在錯誤的數據之上,因為我們的事務可能終止。這就是說明了為什么事務產生的變化,直到事務完成,才對系統的其他部分可見。隔離性不僅僅保 證多個事務不能同時修改相同數據,而且能夠保證事務操作產生的變化直到變化被提交或終止時才能對另一個事務可見,並發的事務彼此之間毫無影響。這就意味着 所有要求修改或讀取的數據已經被鎖定在事務中,直到事務完成才能釋放。大多數數據庫,例如SQL Server以及其他的RDBMS,通過使用鎖定來實現隔離,事務中涉及的各個數據項或數據集使用鎖定來防止並發訪問。
4、持久性 (Durabilily)
持久性意味着一旦事務執行成功,在系統中產生的所有變化將是永久的。應該存在一些檢查點防止在系統失敗時丟失信息。甚至硬件本身失敗,系統的狀態仍能通過在日志中記錄事務完成的任務進行重建。持久性的概念允許開發者認為不管系統以后發生了什么變化,完
成的事務是系統永久的部分。 在銀行的例子中,資金的轉移是永久的,一直保持在系統中。這聽起來似乎簡單,但這,依賴於將數據寫入磁盤,特別需要指出的是,在事務完全完成並提交后才寫 入磁盤的。 所有這些事務特性,不管其內部如何關聯,僅僅是保證從事務開始到事務完成,不管事務成功與否,都能正確地管理事務涉及的數據 ,當事務處理系統創建事務 時,將確保事務有某些特性。組件的開發者們假設事務的特性應該是一些不需要他們親自管理的特性。
二、為什么需要對事務並發控制
如果不對事務進行並發控制,我們看看數據庫並發操作是會有那些異常情形
1、丟失更新(Lost update)
兩個事務都同時更新一行數據,但是第二個事務卻中途失敗退出,導致對數據的兩個修改都失效了。
2、臟讀(Dirty Reads)
一個事務開始讀取了某行數據,但是另外一個事務已經更新了此數據但沒有能夠及時提交。這是相當危險的,因為很可能所有的操作都被回滾。
3、非重復讀(Non-repeatable Reads)
一個事務對同一行數據重復讀取兩次,但是卻得到了不同的結果。同一查詢在同一事務中多次進行,由於其他提交事務所做的修改或刪除,每次返回不同的結果集,此時發生非重復讀。
4、二類丟失更新(Second lost updates problem)
無法重復讀取的特例。有兩個並發事務同時讀取同一行數據,然后其中一個對它進行修改提交,而另一個也進行了修改提交。這就會造成第一次寫操作失效。
5、幻像讀(Phantom Reads)
事務在操作過程中進行兩次查詢,第二次查詢的結果包含了第一次查
詢中未出現的數據(這里並不要求兩次查詢的SQL語句相同)。這是因為在兩次查詢過程中有另外一個事務插入數據造成的。
三、數據庫的隔離級別
為了兼顧並發效率和異常控制,在標准SQL規范中,定義了4個事務隔離級別,(ORACLE和SQLSERER對標准隔離級別有不同的實現 )
1、未提交讀(Read Uncommitted)
直譯就是"讀未提交",意思就是即使一個更新語句沒有提交,但是別
的事務可以讀到這個改變.這是很不安全的。允許任務讀取數據庫中未提交的數據更改,也稱為臟讀。
2、提交讀(Read Committed)
直譯就是"讀提交",可防止臟讀,意思就是語句提交以后即執行了COMMIT以后
別的事務就能讀到這個改變. 只能讀取到已經提交的數據。Oracle等多數數據庫默認都是該級別
3、可重復讀(Repeatable Read):
直譯就是"可以重復讀",這是說在同一個事務里面先后執行同一個查詢語句的時候,得到的結果是一樣的.在同一個事務內的查詢都是事務開始時刻一致的,InnoDB默認級別。在SQL標准中,該隔離級別消除了不可重復讀,但是還存在幻象讀
4、串行讀(Serializable)
直譯就是"序列化",意思是說這個事務執行的時候不允許別的事務並發執行. 完全串行化的讀,每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞
四,隔離級別對事務並發的控制
下表是各隔離級別對各種異常的控制能力。
LU丟失更新 | DR臟讀 | NRR非重復讀 | SLU二類丟失更新 | PR幻像讀 | |
未提交讀 RU | Y | Y | Y | Y | Y |
提交讀 RC | N | N | Y | Y | Y |
可重復讀 RR | N | N | N | N | Y |
串行讀 S | N | N | N | N | N |
順便舉一小例。
My_SQL:
--事務一
set transaction isolation level serializable
begin tran
insert into test values('xxx')
--事務二
set transaction isolation level read committed
begin tran
select * from test
--事務三
set transaction isolation level read uncommitted
begin tran
select * from test
在查詢分析器中執行事務一后,分別執行事務二,和三。結果是事務二會等待,而事務三則會執行。
ORACLE:
--事務一
set transaction isolation level serializable;
insert into test values('xxx');
select * from test;
--事務二
set transaction isolation level read committed--ORACLE默認級別
select * from test
執行事務一后,執行事務二。結果是事務二只讀出原有的數據,無視事務一的插入操作。
五、並發一致性問題的解決辦法
1 封鎖(Locking)
封鎖是實現並發控制的一個非常重要的技術。所謂封鎖就是事務T在對某個數據對象例如表、記錄等操作之前,先向系統發出請求,對其加鎖。加鎖后事務T就對該 數據對象有了一定的控制,在事務T釋放它的鎖之前,其它的事務不能更新此數據對象。 基本的封鎖類型有兩種:排它鎖(Exclusive locks 簡記為X鎖)和共享鎖(Share locks 簡記為S鎖)。
排它鎖又稱為寫鎖。若事務T對數據對象A加上X鎖,則只允許T讀取和修改A,其它任何事務都不能再對A加任何類型的鎖,直到T釋放A上的鎖。這就保證了其它事務在T釋放A上的鎖之前不能再讀取和修改A。
共享鎖又稱為讀鎖。若事務T對數據對象A加上S鎖,則其它事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖。這就保證了其它事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改。
2 封鎖協議
在 運用X鎖和S鎖這兩種基本封鎖,對數據對象加鎖時,還需要約定一些規則,例如應何時申請X鎖或S鎖、持鎖時間、何時釋放等。我們稱這些規則為封鎖協議 (Locking Protocol)。對封鎖方式規定不同的規則,就形成了各種不同的封鎖協議。下面介紹三級封鎖協議。三級封鎖協議分別在不同程度上解決了丟失的修改、不 可重復讀和讀"臟"數據等不一致性問題,為並發操作的正確調度提供一定的保證。下面只給出三級封鎖協議的定義,不再做過多探討。
1 級封鎖協議是:事務T在修改數據R之前必須先對其加X鎖,直到事務結束才釋放。事務結束包括正常結束(COMMIT)和非正常結束(ROLLBACK)。 1級封鎖協議可防止丟失修改,並保證事務T是可恢復的。在1級封鎖協議中,如果僅僅是讀數據不對其進行修改,是不需要加鎖的,所以它不能保證可重復讀和不 讀"臟"數據。
2級封鎖協議是:1級封鎖協議加上事務T在讀取數據R之前必須先對其加S鎖,讀完后即可釋放S鎖。2級封鎖協議除防止了丟失修改,還可進一步防止讀"臟"數據。
3級封鎖協議是:1級封鎖協議加上事務T在讀取數據R之前必須先對其加S鎖,直到事務結束才釋放。3級封鎖協議除防止了丟失修改和不讀'臟'數據外,還進一步防止了不可重復讀。
六、一般處理並發問題時的步驟:
1、開啟事務。
2、申請寫權限,也就是給對象(表或記錄)加鎖。
3、假如失敗,則結束事務,過一會重試。
4、假如成功,也就是給對象加鎖成功,防止其他用戶再用同樣的方式打開。
5、進行編輯操作。
6、寫入所進行的編輯結果。
7、假如寫入成功,則提交事務,完成操作。
8、假如寫入失敗,則回滾事務,取消提交。
9、(7.8)兩步操作已釋放了鎖定的對象,恢復到操作前的狀態。
鎖和隔離級別的關系
一般來說,實際開發中,直接操作數據庫中各種鎖的幾率相對比較少,更多的是利用數據庫提供的四個隔離級別,未提交讀、已提交讀、可重復讀、可序列化,那隔離級別和鎖是什么關系?通俗來說,隔離級別是鎖的一個整體打包解決方案,我的理解是隔離封裝了鎖。
隔離級別從上到下依次增加,級別越低,引起的問題也就比較多,比如臟讀、丟失更新等,但等級越高,也就意味着需要管理更多的鎖,無法並行處理,性能方面又受損,因此,我們在設計系統時,只需要根據業務需求選擇一種當下適合的隔離級別。一種隔離級別,就有一套利用鎖的方案,如此設計,目的就是為了平衡性能和功能。
為什么要使用事務的隔離級別?
對於同時運行的多個事務, 當這些事務訪問數據庫中相同的數據時, 如果沒有采取必要的隔離機制, 就會導致各種並發問題:
• 臟讀: 對於兩個事物 T1, T2; T1 讀取了已經被 T2 更新但還沒有被提交的字段. 之后, 若 T2 回滾, T1讀取的內容就是臨時且無效的.
• 不可重復讀: 對於兩個事物 T1, T2; T1 讀取了一個字段, 然后 T2 更新了該字段. 之后, T1再次讀取同一個字段, 值就不同了.
• 幻讀: 對於兩個事物 T1, T2 ; T1 從一個表中讀取了一個字段, 然后 T2 在該表中插入了一些新的行. 之后, 如果 T1 再次讀取同一個表, 就會多出幾行.
數據庫事務的隔離性: 數據庫系統必須具有隔離並發運行各個事務的能力, 使它們不會相互影響, 避免各種並發問題.
一個事務與其他事務隔離的程度稱為隔離級別. 數據庫規定了多種事務隔離級別, 不同隔離級別對應不同的干擾程度, 隔離級別越高, 數據一致性就越好, 但並發性越弱
數據庫提供了4中隔離級別:
隔離級別 描述
READ UNCOMMITTED(讀未提交數據) 允許事務讀取未被其他事務提交的變更,臟讀、不可重復讀和幻讀的問題都會出現
READ COMMITED(讀已提交數據) 只允許事務讀取已經被其他事務提交的變更,可以避免臟讀,但不可重復讀和幻讀問題仍然會出現
REPEATABLE READ(可重復讀) 確保事務可以多次從一個字段中讀取相同的值,在這個事務持續期間,禁止其他事務對這個字段進行更新,可以避免臟讀和不可重復讀,但幻讀的問題依然存在
SERIALIZABLE(串行化) 確保事務可以從一個表中讀取相同的行,在這個事務持續期間,禁止其他事務對該表執行插入、更新和刪除操作,所有並發問題都可以避免,但性能十分低
事務的隔離級別受到數據庫的限制,不同的數據庫支持的的隔離級別不一定相同
Oracle 支持的 2 種事務隔離級別:READ COMMITED, SERIALIZABLE. Oracle 默認的事務隔離級別為: READ COMMITED
Mysql 支持 4 種事務隔離級別. Mysql 默認的事務隔離級別為: REPEATABLE READ
具體使用
-
以上的四個事務隔離級別都是在Connection接口中定義的靜態常量,
-
使用setTransactionIsolation(int level) 方法可以設置事務隔離級別。
如:con.setTransactionIsolation(Connection.REPEATABLE_READ);