事務具有ACID四種特性:
1、原子性(Atomicity):事務中的操作作爲一個原子操作,其要麼全部執行,要麼都不執行,不可以部分執行。比如銀行的轉賬服務,這個事務的最終結果一定是:某個賬戶的餘額增加了x,而另外一個賬戶的餘額減少了x,或者兩個賬戶的餘額未發生變化。而不會出現其他情況。
2、一致性(Consistent):在事務開始和完成時,數據都必須保持一致狀態。
3、隔離型(Isolation): 數據庫系統提供一定的隔離機制,保證事務不受外部併發操作的影響,在“獨立"的環境中運行,事務的中間狀態對外部不可見,反之亦然。比如轉賬過程中,用戶是不能查詢到一個賬戶餘額減少了,而另外一個賬戶餘額未發生變化的情況。
4、持久性(Durable): 事務完成之後,對數據的修改是永久的,即使系統故障也能保持。
事務處理中主要的問題:
2、髒讀(Dirty Reads):一個事務正在對一條記錄做修改,在這個事務完成並提交前,這條記錄的數據就處於不一致狀態;這時,另一個事務也來讀取同一條記錄,如果不加控制,第二個事務讀取了這些“髒”數據,並據此做進一步的處理,就會產生對未提交的數據依賴關係。這種現象被形象地叫做"髒讀"。
3、不可重複讀(Non-Repeatable Reads):一個事務在讀取某些數據後的某個時間,再次讀取以前讀過的數據,卻發現其讀出的數據已經發生了改變、或某些記錄已經被刪除了。這種現象就叫做“不可重複讀”。
4、幻讀(Phantom Reads):一個事務按相同的查詢條件重新讀取以前檢索過的數據,卻發現其他事務插入了滿足其查詢條件的新數據,這種現象就稱爲“幻讀”。(網上大部分人說法)。在一個事務裏,查詢的結果都是事務開始時的狀態(保證了可重複讀),但是如果另一個事務同時提交了新數據,本事務再更新時,會”驚奇的“發現這些新數據,貌似之前看到的數據是”鬼影“一樣的幻覺。(部分的說法)。
不可重複讀關注點在讀取的數據本身的變化。 幻讀關注點在數據的集合的變化。
事務的隔離型
SQL2標準定義了四種隔離級別:
讀未提交(Read uncommitted):另一個事務修改了數據,但尚未提交,本事務中的SELECT可以讀取到這些未提交的數據(髒讀)。
讀已提交(Read committed):本事務讀取到的是最新的數據(其他事務已經提交的數據都可讀取到)。但是導致的問題是同一個事務裏,前後兩次相同的SELECT讀取到的結果會不同(不可重複讀)。
可重複讀(Repeatable read):同一事務中,SELECT的結果是事務開始的時間點的狀態,同樣的SELECT操作讀取的結果是一致的。但是可能有幻讀現象。
可串行化(Serializable):讀操作也會隱式的獲取共享鎖,從而保證不同事務間的互斥性。
上述的四個級別依次增強。隔離級別越低,併發性能越好。
其中mysql InnoDB的默認隔離級別是可重複讀,利用MVCC提供一致性讀。
不同隔離級別下存在的問題如下:
隔離級 |
髒讀 |
不可重複讀 |
幻讀 |
讀未提交 (Read uncommitted) |
可能 |
可能 |
可能 |
讀提交 (Read committed) |
不可能 |
可能 |
可能 |
可重複讀 (Repeatable read) |
不可能 |
不可能 |
可能 |
可串行化 (Serializable) |
不可能 |
不可能 |
不可能 |
在Mysql的InnoDB引擎中,默認提供的可重複讀的隔離級別,可能會存在幻讀,但是可以通過next-key locking的策略避免幻讀。
session1 | session2 | |
---|---|---|
1 | start transaction; | |
2 | start transaction; | |
3 |
select * from test where id > 17; |
|
4 |
insert into test(id,name,age,create_time) values(23,'test2',21,now()); |
|
5 | commit | |
6 |
select * from test where id > 17; |
|
7 | update test set age = 23 where id > 17; | |
8 |
select * from test where id > 17; 多出來一行記錄 |
|
9 |
上述的問題可以通過使用select for update來避免。 此時就涉及到mysql的相應的鎖機制的問題了,不在此展開了。
refer:
http://www.bitscn.com/pdb/mysql/201405/227973.html
http://bbs.csdn.net/topics/120024254
http://www.cnblogs.com/hustcat/archive/2009/10/18/1585626.html
http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html#isolevel_repeatable-read