關於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.sina.com.cn/s/blog_4c197d420101awhc.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章