1、事務的4個基本特徵
當事務處理系統建立事務時,將確保事務有某些特性。組件的開發者們假設事務的特性應該是一些不須要他們親自管理的特性。這些特性稱爲ACID特性。 ACID就是:原子性(Atomicity )、一致性( Consistency )、隔離性或獨立性( Isolation)和持久性(Durabilily)。
一、原子性 (Atomicity )
原子性屬性用於標識事務是否徹底地完成,一個事務的任何更新要在系統上徹底完成,若是因爲某種緣由出錯,事務不能完成它的所有任務,系統將返回到事務開始前的狀態。
讓咱們再看一下銀行轉賬的例子。若是在轉賬的過程當中出現錯誤,整個事務將會回滾。只有當事務中的全部部分都成功執行了,纔將事務寫入磁盤並使變化 永久化。爲了提供回滾或者撤消未提交的變化的能力,許多數據源採用日誌機制。例如,SQL Server使用一個預寫事務日誌,在將數據應用於(或提交到)實際數據頁面前,先寫在事務日誌上。可是,其餘一些數據源不是關係型數據庫管理系統 (RDBMS),它們管理未提交事務的方式徹底不一樣。只要事務回滾時,數據源能夠撤消全部未提交的改變,那麼這種技術應該可用於管理事務。
二、一致性( Consistency )
事務在系統完整性中實施一致性,這經過保證系統的任何事務最後都處於有效狀態來實現。若是事務成功地完成,那麼系統中全部變化將正確地應用,系統處於有效狀態。若是在事務中出現錯誤,那麼系統中的全部變化將自動地回滾,系統返回到原始狀態。由於事務開
始時系統處於一致狀態,因此如今系統仍然處於一致狀態。 再讓咱們回頭看一下銀行轉賬的例子,在賬戶轉換和資金轉移前,賬戶處於有效狀態。若是事務成功地完成,而且提交事務,則賬戶處於新的有效的狀態。若是事務出錯,終止後,賬戶返回到原先的有效狀態。
記住,事務不負責實施數據完整性,而僅僅負責在事務提交或終止之後確保數據返回到一致狀態。理解數據完整性規則並寫代碼實現完整性的重任一般落在 開發者肩上,他們根據業務要求進行設計。 當許多用戶同時使用和修改一樣的數據時,事務必須保持其數據的完整性和一致性。所以咱們進一步研究A C I D特性中的下一個特性:隔離性。
三、隔離性 ( Isolation)
在隔離狀態執行事務,使它們好像是系統在給定時間內執行的惟一操做。若是有兩個事務,運行在相同的時間內,執行相同的功能,事務的隔離性將確保每一事務在 系統中認爲只有該事務在使用系統。 這種屬性有時稱爲串行化,爲了防止事務操做間的混淆,必須串行化或序列化請求,使得在同一時間僅有一個請求用於同一數據。重要的是,在隔離狀態執行事務, 系統的狀態有多是不一致的,在結束事務前,應確保系統處於一致狀態。可是在每一個單獨的事務中,系統的狀態可能會發生變化。若是事務不是在隔離狀態運行, 它就可能從系統中訪問數據,而系統可能處於不一致狀態。經過提供事務隔離,能夠阻止這類事件的發生。在銀行的示例中,這意味着在這個系統內,其餘過程和事 務在咱們的事務完成前看不到咱們的事務引發的任何變化,這對於終止的狀況很是重要。若是有另外一個過程根據賬戶餘額進行相應處理,而它在咱們的事務完成前就 能看到它形成的變化,那麼這個過程的決策可能
創建在錯誤的數據之上,由於咱們的事務可能終止。這就是說明了爲何事務產生的變化,直到事務完成,纔對系統的其餘部分可見。隔離性不只僅保 證多個事務不能同時修改相同數據,並且可以保證事務操做產生的變化直到變化被提交或終止時才能對另外一個事務可見,併發的事務彼此之間毫無影響。這就意味着 全部要求修改或讀取的數據已經被鎖定在事務中,直到事務完成才能釋放。大多數數據庫,例如SQL Server以及其餘的RDBMS,經過使用鎖定來實現隔離,事務中涉及的各個數據項或數據集使用鎖定來防止併發訪問。
四、持久性 (Durabilily)
持久性意味着一旦事務執行成功,在系統中產生的全部變化將是永久的。應該存在一些檢查點防止在系統失敗時丟失信息。甚至硬件自己失敗,系統的狀態仍能經過在日誌中記錄事務完成的任務進行重建。持久性的概念容許開發者認爲無論系統之後發生了什麼變化,完
成的事務是系統永久的部分。 在銀行的例子中,資金的轉移是永久的,一直保持在系統中。這聽起來彷佛簡單,但這,依賴於將數據寫入磁盤,特別須要指出的是,在事務徹底完成並提交後才寫 入磁盤的。 全部這些事務特性,無論其內部如何關聯,僅僅是保證從事務開始到事務完成,無論事務成功與否,都能正確地管理事務涉及的數據 ,當事務處理系統建立事務 時,將確保事務有某些特性。組件的開發者們假設事務的特性應該是一些不須要他們親自管理的特性。
2、爲何須要對事務併發控制
若是不對事務進行併發控制,咱們看看數據庫併發操做是會有那些異常情形
一、丟失更新(Lost update)
兩個事務都同時更新一行數據,可是第二個事務卻中途失敗退出,致使對數據的兩個修改都失效了。
二、髒讀(Dirty Reads)
一個事務開始讀取了某行數據,可是另一個事務已經更新了此數據但沒有可以及時提交。這是至關危險的,由於極可能全部的操做都被回滾。
三、非重複讀(Non-repeatable Reads)
一個事務對同一行數據重複讀取兩次,可是卻獲得了不一樣的結果。同一查詢在同一事務中屢次進行,因爲其餘提交事務所作的修改或刪除,每次返回不一樣的結果集,此時發生非重複讀。
四、二類丟失更新(Second lost updates problem)
沒法重複讀取的特例。有兩個併發事務同時讀取同一行數據,而後其中一個對它進行修改提交,而另外一個也進行了修改提交。這就會形成第一次寫操做失效。
五、幻像讀(Phantom Reads)
事務在操做過程當中進行兩次查詢,第二次查詢的結果包含了第一次查
詢中未出現的數據(這裏並不要求兩次查詢的SQL語句相同)。這是由於在兩次查詢過程當中有另一個事務插入數據形成的。
3、數據庫的隔離級別
爲了兼顧併發效率和異常控制,在標準SQL規範中,定義了4個事務隔離級別,(ORACLE和SQLSERER對標準隔離級別有不一樣的實現 )
一、未提交讀(Read Uncommitted)
直譯就是"讀未提交",意思就是即便一個更新語句沒有提交,可是別
的事務能夠讀到這個改變.這是很不安全的。容許任務讀取數據庫中未提交的數據更改,也稱爲髒讀。
二、提交讀(Read Committed)
直譯就是"讀提交",可防止髒讀,意思就是語句提交之後即執行了COMMIT之後
別的事務就能讀到這個改變. 只能讀取到已經提交的數據。Oracle等多數數據庫默認都是該級別
三、可重複讀(Repeatable Read):
直譯就是"能夠重複讀",這是說在同一個事務裏面前後執行同一個查詢語句的時候,獲得的結果是同樣的.在同一個事務內的查詢都是事務開始時刻一致的,InnoDB默認級別。在SQL標準中,該隔離級別消除了不可重複讀,可是還存在幻象讀
四、串行讀(Serializable)
直譯就是"序列化",意思是說這個事務執行的時候不容許別的事務併發執行. 徹底串行化的讀,每次讀都須要得到表級共享鎖,讀寫相互都會阻塞 mysql
四,隔離級別對併發的控制
下表是各隔離級別對各類異常的控制能力。 sql
|
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 |
順便舉一小例。 數據庫
MS_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
執行事務一後,執行事務二。結果是事務二隻讀出原有的數據,無視事務一的插入操做。 session
MYSQL
查看InnoDB系統級別的事務隔離級別:
如下爲引用的內容:
mysql> SELECT @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set (0.00 sec)
查看InnoDB會話級別的事務隔離級別:
如下爲引用的內容:
mysql> SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)
修改事務隔離級別:
如下爲引用的內容:
mysql> set global transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)
mysql> set session transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)
InnoDB的可重複讀隔離級別和其餘數據庫的可重複讀是有區別的,不會形成幻象讀(phantom read),所謂幻象讀,就是同一個事務內,屢次select,能夠讀取到其餘session insert並已經commit的數據。下面是一個小的測試,證實InnoDB的可重複讀隔離級別不會形成幻象讀。測試涉及兩個session,分別爲 session 1和session 2,隔離級別都是repeateable read,關閉autocommit
如下爲引用的內容:
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)
mysql> set autocommit=off;
Query OK, 0 rows affected (0.00 sec)
session 1 建立表並插入測試數據
mysql> create table test(i int) engine=innodb;
Query OK, 0 rows affected (0.00 sec) 併發
mysql> insert into test values(1);
Query OK, 1 row affected (0.00 sec)
session 2 查詢,沒有數據,正常,session1沒有提交,不容許髒讀
mysql> select * from test;
Empty set (0.00 sec)
session 1 提交事務
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
session 2 查詢,仍是沒有數據,沒有產生幻象讀
mysql> select * from test;
Empty set (0.00 sec)
以上試驗版本:
mysql> select version();
+-------------------------+
| version() |
+-------------------------+
| 5.0.37-community-nt-log |
+-------------------------+
1 row in set (0.00 sec) 測試
5、併發一致性問題的解決辦法
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級封鎖協議除防止了丟失修改和不讀'髒'數據外,還進一步防止了不可重複讀。
6、通常處理併發問題時的步驟:
一、開啓事務。
二、申請寫權限,也就是給對象(表或記錄)加鎖。
三、假如失敗,則結束事務,過一會重試。
四、假如成功,也就是給對象加鎖成功,防止其餘用戶再用一樣的方式打開。
五、進行編輯操做。
六、寫入所進行的編輯結果。
七、假如寫入成功,則提交事務,完成操做。
八、假如寫入失敗,則回滾事務,取消提交。
九、(7.8)兩步操做已釋放了鎖定的對象,恢復到操做前的狀態。 設計