1. 程式人生 > >【綜合】事務的處理及隔離級別

【綜合】事務的處理及隔離級別

產生 數據表 查看 普通 模式 再次 blank 並發執行 gpo

原文地址:http://blog.csdn.net/qiaoge134/article/details/20031949

事務的隔離級別:

先說說 (通俗說)

1. 臟讀:是一個事務讀取了 其他事務沒有提交的數據。

2.不可重復度:就是第一次讀和第二次讀,兩次讀到的 數據不一致,原因是:在此期間有其他的事務修改了數據。

3.幻讀:就是第一次讀和第二次讀,兩次讀到的 數據不一致,

原因是:在此期間有事務插入了新的數據(區別於不可重復讀:不可重復讀是 對於修改操作而言,幻讀對插入造作而言)

事務的隔離級別有:read-uncommite(讀沒提交),read-commite(讀已提交),none-repeatedRead(不可重復度),serializable(序列化,順序化)

一般的 數據庫都不存在 第一種read-uncommite的情況。

一般數據庫都有自己默認的事務隔離級別;一般情況是 read-commite,這個解決了臟讀的問題,並且效率高 。

人們為了讓 數據庫的效率高並且可以隔離級別高,就出來了 “樂觀鎖”和“悲觀鎖”的思想。

簡單理解:樂觀鎖:當一個事務讀取數據後,要進行操作,在操作前 為數據加一個版本信息(version),當在操作期間有其他事物對改數據進行了操作,那麽版本信息就會變

化,這樣當改事務執行結束後判斷一下版本信息,如果沒變,那麽提交事務,如果改變了,那麽重復執行上述操作---這就是樂觀鎖的思想,很多地方用到這個思想,比如安卓的

數據庫sqlite就又到了version。

悲觀鎖:是當一個事務對 數據進行操作的時候對數據加“鎖”,在此事務沒有提交之前,其他事務是不能操作該數據的,只有這個事務結束提交後,其他事物才能對它進行操作。

當然,很明顯,樂觀鎖的性能要優於悲觀鎖。。。

原文地址:http://blog.sina.com.cn/s/blog_4c197d420101awhc.html

關於MySQL的事務處理及隔離級別

事務是DBMS得執行單位。它由有限得數據庫操作序列組成得。但不是任意得數據庫操作序列都能成為事務。一般來說,事務是必須滿足4個條件(ACID) 原子性(Autmic):事務在執行性,要做到“要麽不做,要麽全做!”,就是說不允許事務部分得執行。即使因為故障而使事務不能完成,在rollback時也要消除對數據庫得影響! 一致性(Consistency)
:事務操作之後,數據庫所處的狀態和業務規則是一致的;比如a,b賬戶相互轉賬之後,總金額不變! 隔離性(Isolation):如果多個事務並發執行,應像各個事務獨立執行一樣! 持久性(Durability):事務提交後被持久化到數據庫. MYSQL的事務處理主要有兩種方法。 1、用BEGIN,ROLLBACK,COMMIT來實現 開始:START TRANSACTION或BEGIN語句可以開始一項新的事務 提交:COMMIT可以提交當前事務,是變更成為永久變更 回滾:ROLLBACK可以回滾當前事務,取消其變更 2、直接用set來改變mysql的自動提交模式 MYSQL默認是自動提交的,也就是你提交一個QUERY,它就直接執行! 我們可以通過set autocommit=0 禁止自動提交 set autocommit=1 開啟自動提交 來實現事務的處理。 但註意當你用 set autocommit=0 的時候,你以後所有的SQL都將做為事務處理,直到你用commit確認或rollback結束,並且只用於當前連接 ※ MYSQL中只有INNODB和BDB類型的數據表才能支持事務處理!其他的類型是不支持! 自己的理解(關於臟讀,不可重復讀,幻讀) ※臟讀:一個事務讀取了另一個未提交的並行事務寫的數據。 (事務T1更新了一行記錄的內容,但是並沒有提交所做的修改。事務T2讀取更新後的行,然後T1執行回滾操作,取消了剛才所做的修改。現在T2所讀取的行就無效了。) exp: 小明的分數為89,事務A中把他的分數改為98,但事務A尚未提交。 與此同時, 事務B正在讀取小明的分數,讀取到小明的分數為98。 隨後, 事務A發生異常,而回滾了事務。小明的分數又回滾為89。 最後, 事務B讀取到的小明的分數為98的數據即為臟數據,事務B做了一次臟讀。 (大部分數據庫缺省的事物隔離級別都不會出現這種狀況) ※不可重復讀:一個事務重新讀取前面讀取過的數據,發現該數據已經被另一個已提交的事務修改過。 (事務T1讀取一行記錄,緊接著事務T2修改了T1剛才讀取的那一行記錄。然後T1又再次讀取這行記錄,發現與剛才讀取的結果不同。這就稱為“不可重復”讀,因為T1原來讀取的那行記錄已經發生了變化。) exp: 在事務A中,讀取到小明的分數為89,操作沒有完成,事務還沒提交。 與此同時, 事務B把小明的分數改為98,並提交了事務。 隨後, 在事務A中,再次讀取小明的分數,此時工資變為98。在一個事務中前後兩次讀取的結果並不致,導致了不可重復讀。 ※幻讀:一個事務重新執行一個查詢,返回一套符合查詢條件的行,發現這些行因為其他最近提交的事務而發生了改變。 (事務T1讀取一條指定的WHERE子句所返回的結果集。然後事務T2新插入 一行記錄,這行記錄恰好可以滿足T1所使用的查詢條件中的WHERE 子句的條件。然後T1又使用相同的查詢再次對表進行檢索,但是此時卻看到了事務T2剛才插入的新行。這個新行就稱為“幻像”,因為對T1來說這一行就像突 然出現的一樣。) exp: 目前分數為90分以上的的學生有15人,事務A讀取所有分數為90分以上的的學生人數有15人。 此時,事務B插入一條分數為99的學生記錄。 這是,事務A再次讀取90分以上的的學生,記錄為16人。此時產生了幻讀。 (大部分數據庫缺省的事物隔離級別都會出現這種狀況,此種事物隔離級別將帶來表級鎖) 事務隔離級別描述: READ UNCOMMITTED:幻讀,不可重復讀和臟讀均允許; READ COMMITTED:允許幻讀和不可重復讀,但不允許臟讀; REPEATABLE READ:允許幻讀,但不允許不可重復讀和臟讀; SERIALIZABLE:幻讀,不可重復讀和臟讀都不允許; ORACLE默認的是 READ COMMITTED。 MYSQL默認的是 REPEATABLE READ。 如果數據庫的隔離級別為REAE_UNCOMMITTED, 則其他線程可以看到未提交的數據, 因此就出現臟讀; 如果數據庫隔離級別設為READ_COMMITTED,即沒提交的數據別人是看不見的,就避免了臟讀;但是,正在讀取的數據只獲得了讀取鎖,讀完之後就解鎖,不管當前事務有沒有結束,這樣就容許其他事務修改本事務正在讀取的數據。導致不可重復讀。 REPEATABLE READ因為對正在操作的數據加鎖,並且只有等到事務結束才放開鎖, 則可以避免不可重復讀; REPEATABLE READ只能保證正在被本事務操作的數據不被其他事務修改,卻無法保證有其他事務提交新的數據。 則有可能線程1在操作表T1的時候(特別是統計性的事務),其他線程仍然可以提交新數據到表T1,這樣會導致線程1兩次統計的結果不一致,就像發生幻覺一樣。 SERIALIZABLE因為獲得範圍鎖,且事務是一個接著一個串行執行,則保證了不會發生幻讀。 由此可見,隔離級別越高,受其他事物幹擾越少,並發性能越差。 二個或以上事務在操作同一個共享記錄集時,可能會出現的問題: (A)臟讀 (B)不可重復讀 (C)幻讀 隔離級別: (1)read-uncommit, (2)read-commit, (3)read-repeatable, (4)read-serializable 都是用來阻止上面的問題的,其中: (1)什麽都阻止不了。 (2)阻止(A) (3)阻止(A)(B) (4)阻止(A)(B)(C) (1)->(4)隔離級別越高,性能損失越大。 修改事務的隔離級別: 在MySQL中默認事務隔離級別是可重復讀(Repeatable read).可通過SQL語句查詢: 查看InnoDB系統級別的事務隔離級別: mysql> SELECT @@global.tx_isolation; 結果: +-----------------------+ | @@global.tx_isolation | +-----------------------+ | REPEATABLE-READ | +-----------------------+ 查看InnoDB會話級別的事務隔離級別: mysql> SELECT @@tx_isolation; 結果: +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ 修改事務隔離級別: mysql> set global transaction isolation level read committed; mysql> set session transaction isolation level read committed;

http://blog.csdn.net/endlu/article/details/51531397

Mysql事務隔離級別與鎖

數據庫的事務有幾種特性,例如一致性和隔離性,一般通過加鎖來實現。同時數據庫又是一個高並發的應用,如果加鎖過度或者不當將嚴重影響性能。數據庫提供了幾種隔離級別來供選擇,本文通過解析InnoDB的加鎖機制是如何實現幾種隔離級別,來更深刻的理解mysql的鎖。 兩階段鎖 首先,事務的所操作分為兩個階段:加鎖和解鎖,兩者不想交。因為事務開始時,並不知道會用到哪些數據,所以加鎖階段隨著事務的執行,可能一直在執行。事務結束時,一起將鎖釋放。註意:不相交!這是兩階段鎖的原則,但是有時為了效率也會違反,後面再詳述。這種方法由於加鎖不是一次獲取全部的鎖,可能出現死鎖,但是事務的並發調度是串行化的。 四種隔離級別:
  • Read Uncommit:未提交讀。允許臟讀。
  • Read Commit : 提交讀。只能讀到其他事務已提交的內容。允許不重復讀。
  • Repeated Read : 可重復讀。同一個事務內的查詢與事務開始時是一致的。允許幻讀。Mysql默認的級別。
  • Serializable : 串行化的讀。每次讀都要獲取表級鎖,讀寫互相阻塞。
Read Uncommit一般不會使用到,並且沒有加鎖,所以不討論。 Serializable也比較簡單粗暴,串行化的讀寫就不會有問題,但是效率低下,稱為悲觀鎖。相對於悲觀鎖,樂觀鎖在一定程度上環節了效率的問題。樂觀鎖大多是基於八本紀錄機制實現的,在mysql中為MVCC(多版本並發控制)。我們主要來談MVCC和RC、RR。 MVCC (詳見http://blog.csdn.net/endlu/article/details/51518377) InnoDB總為每一行後面加入了兩個隱藏的列,來實現MVCC。這兩個列分別紀錄了數據最後一次被哪個事務創建、更新的事務號;該事物是否被刪除,被刪除的事務的事務號。事務號是遞增的。雖然這格外增加的存儲空間,每一行都要存儲額外的歷史版本,而且還要定期刪除。但是多版本的實現,為大多數的讀慚怍提供了方便:讀數據只需要根據事務號來讀取某一歷史版本,不用再擔心並發讀寫的問題而加鎖,效率高,並且可以實現隔離級別中要求的只讀取符合條件的值。我們稱這種讀叫快照讀,相反如果讀取當前的最新數據叫當前讀。mysql在RC/RR下的普通select都為快照讀,不用加鎖。 在RR級別下,各種操作在MVCC下會有怎麽樣的效果呢?
  • select時,讀取版本號<=當前事務號並且刪除版本號為空或>當前事務號的行。
  • insert,保存事務號為當前事務號。
  • delete,保存當前事務號為刪除版本號。
  • update,創建新的一行,保存事務號為當前事務號。
快照讀/當前讀 說完MVCC,我們回到隔離級別。上面說的隔離級別的介紹中,關於RR不能解決幻讀的問題,是耳熟能詳的,到處都是這麽寫的。但是實際呢?經過實驗,session A select * from test where age = 12; 然後Session B插入一個age=12的行,Session A再次select,並沒有返回新插入的行。由此可見Mysql中幻讀的讀問題已經解決了。原理就是上文提到的快照讀。但是,當前讀的沖突問題呢?
  • 快照讀:
    • select * from test where ... ;
  • 當前讀:
    • select * from test where ... in share mode ;
    • select * from test where ... for update ;
    • insert
    • update
    • delete
事務的隔離級別實際上是定義了當前讀的級別。為了減少鎖競爭,引入了快照讀,使得普通的select不同加鎖。其他操縱還是需要加鎖的。 為了解決當前讀的幻讀問題,Mysql使用了Next-key鎖。就是GAP(間隙鎖)和行鎖的合並。行鎖可以避免並發修改同一行帶來的問題,但是插入操作呢?間隙鎖GAP就是為了解決這個問題。 在RC級別中,表test,age為主鍵:
  1. A:select * from test where age = 10; 返回一條記錄
  2. A:update test set name = ‘a’ where age = 10;
  3. B:insert into test values(10,‘b’);
  4. B:commit;
  5. A:select * from test where age = 10; 返回兩條記錄
  6. A:commit ;
在這個例子中,步驟二雖然進行了update,對age=10的記錄加了行鎖。但是session B插入了新紀錄,並提交。A就可以讀到。 在RR級別中,重新進行這個實驗,A的第二次讀,仍然返回一條記錄。因為在步驟二中,不止對age=10的行加了行鎖,還有間隙鎖。session B的插入將被阻塞,等待獲取鎖,A提交後才能被執行。 InnoDB行鎖 上面說到,InnoDB當前讀,會對行加鎖,防止並發問題。這裏有個前提:where條件是索引,可以通過索引來過濾行來對指定行加鎖。如果不是索引,InnoDB會對所有行加鎖,但是為了提供並發效率。等存儲系統返回數據後,會過濾後再對不符合條件的行釋放鎖。還記得本文開頭介紹兩階段鎖時,說過有時為了效率會違反這個原則麽。就是現在所說的這種情況。先獲取全部鎖,再釋放掉多余的鎖。 特殊情況 這裏舉一個例子:
  1. A:select * from test where age = 10; 返回一條記錄
  2. B:insert into test values(10,‘b’);
  3. B:commit;
  4. A:update test set name = ‘qwe’where age = 10;
  5. A:select * from test where age = 10; 返回兩條記錄
看到這個結果,有人不禁起了疑問:不是說InnoDB在RR級別解決了幻讀問題麽?怎麽同一個事務中兩次讀讀到了不同的行數。 這裏A的前後兩次讀,均為快照讀,而且是在同一個事務中。但是B先插入直接提交,此時A再update,update屬於當前讀,所以可以作用於新插入的行,並且將改行的當前版本號設為A的事務號,所以第二次的快照讀,是可以讀取到的,因為同事務號。這種情況符合MVCC的規則,如果要稱為一種幻讀也非不可,算為一個特殊情況來看待吧。

【綜合】事務的處理及隔離級別