1. MySQL 事務的四大特性
MySQL 事務具有四個特性:原子性、一致性、隔離性、持久性,這四個特性簡稱 ACID 特性
一、原子性(Atomicity ):一個事務是一個不可再分割的整體,要么全部成功,要么全部失敗
事務在數據庫中就是一個基本的工作單位,事務中包含的邏輯操作(SQL 語句),只有兩種情況:成功和失敗。事務的原子性其實指的就是這個邏輯操作過程具有原子性,不會出現有的邏輯操作成功,有的邏輯操作失敗這種情況
二、一致性(Consistency ):一個事務可以讓數據從一種一致狀態切換到另一種一致性狀態
舉例說明:張三給李四轉賬 100 元,那么張三的余額應減少 100 元,李四的余額應增加 100 元,張三的余額減少和李四的余額增加這是兩個邏輯操作具有一致性
三、隔離性(Isolution ):一個事務不受其他事務的影響,并且多個事務彼此隔離
一個事務內部的操作及使用的數據,對并發的其他事務是隔離的,并發執行的各個事務之間不會互相干擾
四、持久性(Durability ):一個事務一旦被提交,在數據庫中的改變就是永久的,提交后就不能再回滾
一個事務被提交后,在數據庫中的改變就是永久的,即使系統崩潰重新啟動數據庫數據也不會發生改變
2. MySQL 事務的并發問題
上面講到了事務的隔離性,當有多個任務時,應當讓多個事務同時執行,這就是事務的并發。既然事務存在并發執行,那必然存在兩個事務操作同一個數據的沖突問題,那么我們來看一下會出現哪些問題
下面介紹臟讀、不可重復讀、幻讀時會涉及到事務隔離級別,可先略過。按照提示設置事務隔離級別即可,本文后面會介紹事務隔離級別。測試這幾個事務并發問題可以通過打開兩個終端窗口進行測試
查看事務隔離級別
select @@transaction_isolation;
一、臟讀
測試臟讀: 將事務隔離級別修改為讀未提交
# READ-UNCOMMITTED 讀未提交
set session transaction isolation level read uncommitted;
現在有兩個事務,分別是事務 A 和事務 B。在事務 A 中查詢一條數據,查詢結果中 score 的值是 80,然后事務 B 去修改這一條數據,將 score 的值改為 90,但是它沒有提交,這時候事務 A 去查詢這條數據,發現數據竟然發生了變化。
臟讀: 在一個事務里面,由于其他事務修改了數據并且沒有提交,而導致前后兩次讀取的數據不一致的情況,這種事務并發問題稱之為 “臟讀”
二、不可重復讀
測試不可重復讀: 將事務隔離級別修改為讀已提交
# READ-COMMITTED 讀已提交
set session transaction isolation level read committed;
同樣是兩個事務,事務 A 查詢一條數據,事務 B 修改了這條數據,特別注意,這里事務 B 執行了提交,但是事務 A 還沒有提交或回滾,這種事務并發問題稱為不可重復讀
不可重復讀: 一個事務讀取到其他事務已提交的數據導致前后兩次讀取數據不一樣的情況
三、幻讀
測試可重復讀: 將事務隔離級別修改為可重復讀
# REPEATABLE-READ 可重復讀(默認的事務隔離級別)
set session transaction isolation level repeatable read;
幻讀: 一個事務前后兩次讀取的數據不一致,是因為其他事務插入數據導致的事務并發情況
3. MySQL 事務的隔離級別
MySQL 事務有四種隔離級別,如下所示,表格中的 “是” 代表存在這個問題,“否” 代表沒有這個問題
隔離級別 | 臟讀 | 不可重復讀 | 幻讀 |
---|---|---|---|
Read uncommitted(讀未提交) | 是 | 是 | 是 |
Read committed(讀已提交) | 否 | 是 | 是 |
Repeatable read(可重復讀,默認的隔離級別) | 否 | 否 | 是 |
Serializable(可串行化) | 否 | 否 | 否 |
查看事務隔離級別
# 查看全局事務隔離級別
select @@global.tx_isolation;
# 查看會話事務隔離級別(也就是當前窗口)
select @@tx_isolation;
select @@transaction_isolation;
設置事務隔離級別
# 讀未提交
set session transaction isolation level read uncommitted;
# 讀已提交
set session transaction isolation level read committed;
# 可重復讀(默認隔離級別)
set session transaction isolation level repeatable read;
# 可串行化
set session transaction isolation level serializable;
總結:
MySQL 的默認隔離級別是可重復讀,不是讀已提交
隔離性從低到高分別是:讀未提交、讀已提交、可重復讀、可串行化
并發性跟隔離性恰好相反,從低到高是:可串行化、可重復讀、讀已提交、讀未提交
這也非常好理解,隔離性越高,說明鎖的粒度越細,并發性自然就會降低