天天看點

mysql事務隔離級别

1、什麼是事務

事務是一條或多條資料庫操作語句的組合,具備ACID,4個特點。

原子性:要不全部成功,要不全部撤銷

隔離性:事務之間互相獨立,互不幹擾

一緻性:資料庫正确地改變狀态後,資料庫的一緻性限制沒有被破壞

持久性:事務的送出結果,将持久儲存在資料庫中

2、事務并發會産生什麼問題

1)第一類丢失更新:在沒有事務隔離的情況下,兩個事務都同時更新一行資料,但是第二個事務卻中途失敗退出, 導緻對資料的兩個修改都失效了。

例如:

       張三的工資為5000,事務A中擷取工資為5000,事務B擷取工資為5000,彙入100,并送出資料庫,工資變為5100,

       随後

       事務A發生異常,復原了,恢複張三的工資為5000,這樣就導緻事務B的更新丢失了。

2)髒讀:髒讀就是指當一個事務正在通路資料,并且對資料進行了修改,而這種修改還沒有送出到資料庫中,這時,另外一個事務也通路這個資料,然後使用了這個資料。

  張三的工資為5000,事務A中把他的工資改為8000,但事務A尚未送出。

  與此同時,

  事務B正在讀取張三的工資,讀取到張三的工資為8000。

  随後,

  事務A發生異常,而復原了事務。張三的工資又復原為5000。

  最後,

  事務B讀取到的張三工資為8000的資料即為髒資料,事務B做了一次髒讀。

3)不可重複讀:是指在一個事務内,多次讀同一資料。在這個事務還沒有結束時,另外一個事務也通路該同一資料。那麼,在第一個事務中的兩次讀資料之間,由于第二個事務的修改,那麼第一個事務兩次讀到的的資料可能是不一樣的。這樣就發生了在一個事務内兩次讀到的資料是不一樣的,是以稱為是不可重複讀。

  在事務A中,讀取到張三的工資為5000,操作沒有完成,事務還沒送出。

  事務B把張三的工資改為8000,并送出了事務。

  在事務A中,再次讀取張三的工資,此時工資變為8000。在一個事務中前後兩次讀取的結果并不緻,導緻了不可重複讀。

4)第二類丢失更新:不可重複讀的特例。有兩個并發事務同時讀取同一行資料,然後其中一個對它進行修改送出,而另一個也進行了修改送出。這就會造成第一次寫操作失效。 

在事務A中,讀取到張三的存款為5000,操作沒有完成,事務還沒送出。

  事務B,存儲1000,把張三的存款改為6000,并送出了事務。

  在事務A中,存儲500,把張三的存款改為5500,并送出了事務,這樣事務A的更新覆寫了事務B的更新。

5)幻讀:是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的資料進行了修改,這種修改涉及到表中的全部資料行。同時,第二個事務也修改這個表中的資料,這種修改是向表中插入一行新資料。那麼,以後就會發生操作第一個事務的使用者發現表中還有沒有修改的資料行,就好象發生了幻覺一樣。

  目前工資為5000的員工有10人,事務A讀取所有工資為5000的人數為10人。

  此時,

  事務B插入一條工資也為5000的記錄。

  這是,事務A再次讀取工資為5000的員工,記錄為11人。此時産生了幻讀。

提醒:

不可重複讀的重點是修改,同樣的條件,你讀取過的資料,再次讀取出來發現值不一樣了

幻讀的重點在于新增或者删除,同樣的條件,第 1 次和第 2 次讀出來的記錄數不一樣

3、事務隔離級别,解決什麼并發問題,以及存在什麼并發問題

(1)READ_UNCOMMITTED

  這是事務最低的隔離級别,它充許另外一個事務可以看到這個事務未送出的資料。

  解決第一類丢失更新的問題,但是會出現髒讀、不可重複讀、第二類丢失更新的問題,幻讀 。

(2)READ_COMMITTED

  保證一個事務修改的資料送出後才能被另外一個事務讀取,即另外一個事務不能讀取該事務未送出的資料。

  解決第一類丢失更新和髒讀的問題,但會出現不可重複讀、第二類丢失更新的問題,幻讀問題

(3)REPEATABLE_READ

  保證一個事務相同條件下前後兩次擷取的資料是一緻的

       解決第一類丢失更新,髒讀、不可重複讀、第二類丢失更新的問題,但會出幻讀。

(4)SERIALIZABLE

  事務被處理為順序執行。

  解決所有問題

詳情見下表:

MySQL預設的事務隔離級别為repeatable_read

不可重複讀與幻讀的差別:

髒讀的重點是讀另一個事務未送出的資料(假若那個事務RollBack, 則這資料就是無效的):某個事務已更新一份資料, 另一個事務在此時讀取了同一份資料, 由于某些原因, 前一個RollBack了操作, 則後一個事務所讀取的資料就會是不正确的

不可重複讀的重點是修改: 同樣的條件, 你讀取過的資料, 再次讀取出來發現值不一樣了

幻讀的重點在于新增或者删除: 同樣的條件, 第1次和第2次讀出來的記錄數不一樣

當然, 從總的結果來看, 似乎兩者都表現為兩次讀取的結果不一緻, 但如果你從控制的角度來看, 兩者的差別就比較大, 對于不可重複讀, 隻需要鎖住滿足條件的記錄, 對于幻讀, 要鎖住滿足條件及其相近的記錄rollback;或者commit;都會退出事務!

更新記錄的時候需要鎖!

InnoDB中 隻要此行在别的事務中産生了鎖 本事務中就不允許進行修改 隻能阻塞 等待别的事務送出

一般設定為Read Committed, 并且利用悲觀鎖(SELECT ... FOR UPDATE)或樂觀鎖(SET NUM=NUM+1, 而不是計算後再插入, 避免并發)來處理特殊情況

在MySQL中設定事務隔離級别有2種方法:

1 在my.cnf中設定,在mysqld選項中如下設定

[mysqld]

 transaction-isolation = READ-COMMITTED

2 在mysql視窗用set指令重置

設定目前的會話事務級别

  1. mysql> set tx_isolation='REPEATABLE-READ';  
  2. Query OK, 0 rows affected (0.01 sec)  
  3. mysql>  

查詢目前的會話事務級别,可以使用:

  1. mysql> select @@tx_isolation;  
  2. +----------------+  
  3. | @@tx_isolation |  
  4. | READ-COMMITTED |  
  5. 1 row in set (0.00 sec)  

設定全局的會話事務級别

  1. mysql> set global tx_isolation='REPEATABLE-READ';  
  2. mysql>

查詢全局的事務隔離級别,可以使用:

  1. mysql> select @@global.tx_isolation;  
  2. +-----------------------+  
  3. | @@global.tx_isolation |  
  4. | READ-COMMITTED        |  
  5. mysql>