都要面試了還不來學學mysql事務隔離機制?

大家有沒有想過一個問題,我們爲什麼需要事務?事務解決了怎樣的問題?事務又會帶來什麼新的問題?本人也是帶着疑惑一步步去深入學習,特此總結一下。

一、基礎概念

1.1 什麼是事務?

事務(Transaction) 是訪問和更新數據庫的程序執行單元,事務中可能包含一個或多個SQL語句。事務最大的特點就是,要麼SQL語句都執行,要麼都不執行。

1.2 事務條件

事務必須總是滿足以下的四個條件:

  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔離性(Isolation)
  • 持久性(Durability)

以上四個條件簡稱ACID,下文將對事務條件逐一進行講解。

1.2.1 原子性

用一個最簡單的案例來說:

張三李四張三給李四轉賬100元張三餘額應該減100元李四餘額應該加100元張三李四

上面這個轉賬操作,可以分爲三條sql語句:

  1. 查詢張三餘額是否>100元,若滿足則執行後續SQL,否則返回。
  2. 張三餘額減去100元
  3. 李四餘額加100元

在這個案例當中,我們應該確保上面的轉賬操作要麼都成功進行,要麼都失敗,才能確保交易的合法性,即就是事務不會結束在書屋中間某個環節,如果在事務的執行過程中發生錯誤,則會回滾到事務開始的狀態。即滿足了事務的 原子性條件。

1.2.2 一致性

事物的一致性有點難理解,至少對於我是這樣的,而在我搜集很多資料總結的時候,我看到了這麼一句話:事務一致性是:應用系統從一個正確的狀態到另一個正確的狀態,我瞬間恍然大悟了。一致性關注數據的可見性,中間狀態的數據對外部不可見,只有最初狀態和最終狀態的數據對外可見。

1.2.3 隔離性

多個用戶訪問數據庫時,各自的事務具有隔離性,每個事務都有自己的數據空間,不會相互干擾。

1.2.4 持久性

執行事務提交後,數據會永久性保留在硬盤中。

二、事務隔離級別

mysql 8.0+可以查看當前隔離級別:

select @@transaction_isolation;

以前的老版本查看隔離級別是:

select @@tx_isolation;

mysql事務隔離級別分爲以下四種:

事務隔離級別 髒讀 不可重複讀 幻讀
讀未提交 (read-uncommitted)
讀已提交 (read-committed)
可重複讀 (repeatable-read)
串行化 (serializable)

名詞解釋:
髒讀:事務A和事務B同時執行,此時事務A還沒有提交修改的數據,但是事務B讀取到事務A改變後的數據,這就是髒讀。
不可重複讀:事務A讀取一條記錄,此時事務B對該數據 進行了操作(改變了原數據)並提交事務B,此時事務A再次查詢數據與第一次讀取的不一樣,這就是不可重複讀(兩次讀取的不一樣啊,就是說重複讀的話可能會前後矛盾,所以可以理解成不可重複讀。)。
幻讀:事務A、B同時開啓,若數據庫此時有兩條數據(id分別是1,2),事務B此時插入了一條數據(id爲3),同時提交事務B,此時事務A再插入id爲3的數據的時候,會提示插入失敗,但是查詢數據依然只能查到兩條數據,這就是幻讀。
不可重複讀重點在於update和delete,而幻讀的重點在於insert
在進行介紹之前,我們首先創建一個測試表。

CREATE DATABASE study; 
use stydy;
CREATE TABLE person(
		name varchar(20),
		country varchar(20),
		salary decimal,
		id int (11) primary key auto_increment
		);
insert into person(id,name,salary,country) values(1,"小王",1000,"中國");

2.1 讀未提交

讀未提交可能會出現髒讀、不可重複讀、幻讀。
(a)髒讀

髒讀:若同時有多個事務A,B開啓,事務B改變了數據但是沒有提交,但此時事務A中可以讀到事務B中未提交的數據。若此時B事務回滾,則出現了髒讀。

我們先來開啓兩個事務:

事務A 事務B
set session transaction isolation level read uncommitted; set session transaction isolation level read uncommitted;
start transaction; start transaction;
select *from person;
在這裏插入圖片描述
update person set salary=2000 where name=“小王”;
select *from person; 在這裏插入圖片描述
commit; commit;

可以看到,事務B未提交,但是已經影響了事務A,所以這就是髒讀。

2.2 讀已提交

讀已提交不會出現髒讀,但是還是會帶來不可重複讀和幻讀。
(a)不可重複讀:

若同時有多個事務A,B開啓,事務A先讀取一次數據,事務B改變了數據並提交事務B,此時事務A再讀取數據就是被事務B更新過的值,與第一次讀取的結果不一致,這就是不可重複讀。

我們先來開啓兩個事務:

事務A 事務B
set session transaction isolation level read committed; set session transaction isolation level read committed;
start transaction; start transaction;
select *from person;
在這裏插入圖片描述
update person set salary=2000 where name=“小王”;
select *from person;
可以看到已經解決了髒讀在這裏插入圖片描述
commit;
select *from person;在這裏插入圖片描述
commit;

可以看到解決了髒讀,但是還是會出現讀取結果前後不一致的情況。即就是不可重複讀。

2.3 可重複讀

(a)幻讀

兩個事務同時開啓的時候,若一方對數據庫insert數據,則會出現幻讀!

我們先來開啓兩個事務:

事務A 事務B
set session transaction isolation level repeatable-read; set session transaction isolation level repeatable-read;
start transaction; start transaction;
select *from person;
在這裏插入圖片描述
update person set salary=2000 where name=“小王”;
select *from person;
可以看到已經解決了髒讀在這裏插入圖片描述
commit;
select *from person;
可以看到已經解決了不可重複讀 在這裏插入圖片描述
start transaction;
insert person(id,name,salary,country) values(0,“小張”,5000,“加拿大”);
commit;
insert person(id,name,salary,country) values(0,“小張”,5000,“加拿大”);在這裏插入圖片描述
select * from person;
出現了幻讀,明明只有一條數據還是插入失敗? 在這裏插入圖片描述
commit;

2.4 串行化隔離級別

事務隔離級別設置爲串行化時,如果同時開啓多個事務,爲保證其他事務不會幻讀到這個數據,insert數據時會“卡住”,直到其他事務提交。insert纔可以執行完成添加操作,這樣即就解決了幻讀問題!

總結:

以上例子說明了事務隔離級別不同可能會帶來不同的結果,另外事務隔離級別爲串行化時,讀寫數據都會鎖住整張表,隔離級別越高,越能保證數據的完整性和一致性,但是對併發性能的影響也越大。因爲這個並不常用。

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