MySQL | 事務 | 髒讀 | 不可重複讀 | 幻讀 | 隔離級別

目錄

一.事務

1.什麼是事務

2.事務所具有的四個特性

3.原子性

4.一致性

5.隔離性

二.髒讀

1.什麼是髒讀

2.導致髒讀發生的情況

三.不可重複讀

1.不可重複讀

2.不可重複讀問題發生的情況

3.解決不可重複讀問題的方法

四.幻讀

1.什麼是幻讀

2.幻讀發生的情況

3.解決方法

五.持久性

六.隔離級別

1.隔離級別的分類

2.隔離級別的劃分


一.事務

1.什麼是事務

我們一般所講的事務,是MySQL中InnoDB存儲引擎所支持的事務。而所謂的事件簡單的來講幾就是一組特定SQL語句的集合。

2.事務所具有的四個特性

  1. 原子性:一個事務是一個不可分割的工作單位,事務中包括的操作要麼都做(某個語句的集合要麼全部執行成功),要麼都不做(某個語句的集合要麼全部執行失敗)。如果某一步執行失敗了,事務就會回滾到語句執行前的狀態。
  2. 一致性:完整性約束,數據完整性約束指的是爲了防止不符合規範的數據進入數據庫,在用戶對數據進行插入、修改、刪除等操作時,DBMS自動按照一定的約束條件對數據進行監測,使不符合規範的數據不能進入數據庫,以確保數據庫中存儲的數據正確、有效、相容。
  3. 隔離性:一個事務的執行不能被其他事務干擾。即一個事務內部的操作及使用的數據對併發的其他事務是隔離的,併發執行的各個事務之間不能互相干擾。
  4. 持久性:事務執行的結果在磁盤上永久的保存,指一個事務一旦提交,它對數據庫中數據的改變就應該是永久性的。接下來的其他操作或故障不應該對其有任何影響。

這四個屬性通常稱爲ACID特性。

3.原子性

日誌系統中有兩個日誌,分別是

  • 重做日誌(redo log)
  • 未做日誌(undo log)

首先事務在提交以後,重做日誌先記錄這個事務將要執行的操作,接着進行日誌先行,就是將現在重做日誌中存儲的信息刷新到磁盤上,接着纔開始執行事務。假如事務A執行到某一步驟時,系統斷電了,但恢復電力後可以通過重做日誌來查看事務A一共進行了哪些操作以及執行到了哪一個步驟。即重做日誌保證了事務全部執行成功。

未做日誌用來記錄了每一個修改點的狀態(版本),通俗的理解爲每一條數據被修改前和修改後的值。這樣的話,就可以進行事物的回滾了(回到數據一開始的狀態)。即未做日誌保證了事務全部執行失敗。

通過這兩個日誌就保證了事務的原子性。

4.一致性

與原子性密切相關,但是一致性是一個很難理解的概念,如有興趣大家可以參考一下這篇博客:

https://blog.csdn.net/qq_26295547/article/details/79828966

以及知乎的相關回答:

https://www.zhihu.com/question/31346392

5.隔離性

如果沒有隔離性,事務執行過程中會出現什麼問題?

出現髒讀,例如現在在數據庫的某張表中有這樣一條數據

name salary
zhangsan 5000

這條數據的意思是zhangsan的工資爲5000。現在有一個事務A開始執行,首先事務A進行以下操作

/*A---Begin*/

select *
from table_name
where salary = 5000;

updata table_name
set salary = 8000
where name = zhangsan;

當執行到這裏時,事務A已經將zhangsan的工資修改爲了8000,但此時因爲時間輪片法的規則,給事務A分配的時間到了(此時事務A的執行並沒有結束),而此時系統開始執行另一個事務B,事務B進行了下面操作

/*B-----Begin*/

select *
from table_name
where salary = 8000;

此時事務B查找到的結果是 zhangsan的工資爲8000,接着事務B又對這一條數據進行了其他一系列操作,因爲時間輪片法的規則,給事務B分配的時間到了(此時事務B的執行並沒有結束),此時系統又開始執行事務A,若此時事務A又對這條數據進行了其他操作,但某一步執行失敗了,根據事務的原子性,事務A就要回滾到語句執行前的狀態。回滾後 zhangsan的工資又變成了5000,而此時另一個事務B所有的操作都是建立在 zhangsan 的工資爲8000的基礎上,這是事務B所讀到的數據都是髒數據,而基於髒數據所進行的操作都是錯誤的,這種情況就是髒讀。

/*用戶自己執行回滾*/

roolback;

二.髒讀

1.什麼是髒讀

髒讀:事務A修改了一個數據,但未提交,事務B讀到了事務A未提交的更新結果,如果事務A提交失敗,事務B讀到的就是髒數據。

2.導致髒讀發生的情況

事務執行過程中獲取到其他事務執行過程中的結果。

三.不可重複讀

1.不可重複讀

還是同樣的數據

name salary
zhangsan 5000

同樣事務A執行以下操作

/*A---Begin*/

select *
from table_name
where salary = 5000;

updata table_name
set salary = 8000
where name = zhangsan;

接着事務B開始執行(此時事務A並沒有執行結束),事務B進行了以下操作

/*B-----Begin*/

select salary
from table_name
where name = zhangsan;

此時事務B得到的結果是 zhangsan的工資爲5000,接者系統又開始執行事務A,事務B暫時被掛起,而此時事務A什麼操作都沒有進行,接這事務A就結束了。

/*A------End*/

而系統又開始執行事務B,若現在事務B有查詢了一次 zhangsan 的工資

select salary
from table_name
where name = zhangsan;

而此時,zhangsan的工資已經被事務修改爲了8000,所以事務B的這次查詢操作得到的結果就是zhangsan的工資爲8000,我們發現B事務什麼事情都沒有做,只是對同一條數據進行了兩趟查詢操作,卻拿到了兩條不同的數據。這種問題就被稱爲不可重複讀(在同一個事務中,對於同一份數據讀取到的結果不一致。

2.不可重複讀問題發生的情況

事務在執行過程中獲取到了其他不同階段的結果,是修改(updata)操作導致的。

3.解決不可重複讀問題的方法

不可重複讀出現的原因就是事務併發修改記錄,要避免這種情況,最簡單的方法就是對要修改的記錄加鎖,這回導致鎖競爭加劇,影響性能。另一種方法是通過MVCC可以在無鎖的情況下,避免不可重複讀。

四.幻讀

/*A-----Begin*/

insert into table_name
values(lisi,5000);
/*B-----Begin*/
select COUNT(name)
from table_name
where salary = 5000;
/*A-----End*/
select COUNT(name)
from table_name
where salary = 5000;

/*B-----End*/

我們看到,首先執行事務A,事務A向這張表裏插入了一條數據,接着事務A被掛起,事務B開始執行,事務B查詢了工資爲5000的員工的個數,的到的結果是1,接着事務B被掛起,事務A有開始執行,此時事務A沒有進行其他操作,而是事務A執行完畢並關閉,接着事務B又開始執行,此時事務B又查詢了工資爲5000的員工的個數,但得到的結果是2,。

1.什麼是幻讀

在同一個事務中,同一個查詢多次返回的結果不一致。

2.幻讀發生的情況

事務執行過程中獲取到了其他事務不同階段的結果,是由插入(insert)和刪除(delete)導致的。

3.解決方法

間隙鎖,幻讀是由於併發事務增加記錄導致的,這個不能像不可重複讀通過記錄加鎖解決,因爲對於新增的記錄根本無法加鎖。需要將事務串行化,才能避免幻讀。

五.持久性

通過日誌來保證事務的持久性。

六.隔離級別

1.隔離級別的分類

  • 未提交讀(READ-UNCOMMITTED),最低的隔離級別,在這個隔離級別下出現髒讀,不可重複讀,幻讀的問題。
  • 已提交讀(READ-COMMITTED),SQL Server默認的隔離級別就是已提交隔離級別。在這個隔離級別下出現 不可重複讀,幻讀的問題,可以解決髒讀的問題
  • 可重複讀(REPEATABLE-READ),InnoDB存儲引擎默認的隔離級別就是可重複讀隔離級別。在這個隔離級別下出現幻讀的問題,可以解決髒讀吧,不可重複讀問題。
  • 可序列化,隔離級別最高,不會出現上面所述的任何問題,但是效率太低,因爲在這種隔離級別下事務之間的關係是串型的,犧牲了系統的併發性。

可以通過下面命名查看當前系統的隔離級別

select @@tx_isolation;

將隔離級別設置爲 未提交讀 隔離級別

set tx_isolation = "READ-UNCOMMITED";

2.隔離級別的劃分

  • 全局隔離級別:默認爲REPEATABLE-READ,存放在服務器端。
  • 會話隔離級別: 會話隔離級別是複製的服務器端的隔離級別。而客戶端看到的都是會話隔離級別。所以就算用戶將某一會話的隔離級別改變了,其他會話的隔離級別不會改變。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章