一.事務隔離機制介紹
事務具有原子性、一致性、隔離性、持久性四大特性
而隔離性顧名思義指的就是事務彼此之間隔離開, 多個事務在同時處理一個資料時彼此之間互相不影響, 如如果隔離的不夠好就有可能會產生臟讀、不可重復度、幻讀等讀現象
二.隔離性的四個級別
1.等級(隔離程度)由低到高
- Read uncommitted (未提交讀)
- Read committed (提交讀)
- Repeatable read (可重復讀) (mysql默認)
- Serializable (可序列化)
2.依次解決的讀現象
-
? : 可能出現
-
? : 不會出現
| 臟讀 | 不可重復讀 | 幻讀 | |
| Read uncommitted | √ | √ | √ |
| Read committed | × | √ | √ |
| Repeatable read(mysql默認) | × | × | √ |
| Serializable | × | × | × |
需要強調的是 : 我們確實可以采用提高事務的隔離級別的方式來解決臟讀、不可重復讀、幻讀等問題, 但與此同時, 事務的隔離級別越高, 并發能力也就越低; 所以, 還需要讀者根據業務需要進行權衡
三.四種級別介紹
1.未提交讀 (Read uncommitted)
- 定義
是最低的隔離級別, 在這種事務隔離級別下, 一個事務可以讀到另外一個事務未提交的資料
- 資料庫加鎖情況(實作原理)
事務在讀資料的時候并未對資料加鎖
事務在修改資料的時候只對資料增加行級共享鎖
- 現象解釋
事務1讀取某行記錄時, 事務2也能對這行記錄進行讀取、更新, 并且因為事務一并未對資料增加任何鎖
當事務2也對該記錄進行更新時, 事務1再次讀取該記錄, 能讀到事務2對該記錄的修改版本 (因為事務2只增加了共享讀鎖, 事務1可以再增加共享讀鎖讀取資料), 即使該修改尚未被提交, 若此時事務2回滾, 那事務1讀到的就臟資料了, 這就引發了臟讀現象
事務1更新某行記錄時, 事務2不能對這行記錄做更新, 直到事務1結束 (因為事務1對資料增加了共享讀鎖, 事務2不能增加排他寫鎖進行資料的修改)
2.提交讀 (Read committed)
- 定義
可以理解成都已提交, 在一個事務修改資料程序中, 如果事務還沒提交, 其他事務不能讀該資料
- 資料庫加鎖情況
事務對當前被讀取的資料增加行級共享鎖(讀到時才加鎖), 一旦讀完該行, 立即釋放該行行級共享鎖
事務在更新某資料的瞬間(在更新的瞬間), 必須先對其加行級排它鎖, 直到事務結束才釋放
- 現象解釋
事務1在讀取某行記錄的整個程序中, 事務2都可以對該行記錄進行讀取 (因為事務一對該行記錄增加行級共享鎖的情況下, 事務二同樣可以對該資料增加共享鎖來讀資料)
事務1讀取某行的一瞬間, 事務2不能修改該行資料, 但是, 只要事務1讀取完改行資料, 事務2就可以對該行資料進行修改 (事務一在讀取的一瞬間會對資料增加共享鎖, 任何其他事務都不能對該行資料增加排他鎖; 但是事務一只要讀完該行資料, 就會釋放行級共享鎖, 一旦鎖釋放, 事務二就可以對資料增加排他鎖并修改資料)
事務1更新某行記錄時, 事務2不能對這行記錄做更新, 直到事務1結束 (事務一在更新資料的時候, 會對該行資料增加排他鎖, 知道事務結束才會釋放鎖, 所以, 在事務二沒有提交之前, 事務一都能不對資料增加共享鎖進行資料的讀取; 所以, 提交讀可以解決臟讀的現象)
3.可重復讀 (Repeatable reads)
- 定義
由于提交讀隔離級別會產生不可重復讀的讀現象, 所以比提交讀更高一個級別的隔離級別就可以解決不可重復讀的問題, 這種隔離級別就叫可重復讀
- 資料庫鎖情況
事務在讀取某資料的瞬間 (就是開始讀取的瞬間), 必須先對其加行級共享鎖, 直到事務結束才釋放
事務在更新某資料的瞬間 (就是發生更新的瞬間), 必須先對其加行級排他鎖, 直到事務結束才釋放
- 現象解釋
事務1在讀取某行記錄的整個程序中, 事務2都可以對該行記錄進行讀取 (因為事務一對該行記錄增加行級共享鎖的情況下, 事務二同樣可以對該資料增加共享鎖來讀資料)
事務1在讀取某行記錄的整個程序中, 事務2都不能修改該行資料 (事務一在讀取的整個程序會對資料增加共享鎖, 直到事務提交才會釋放鎖, 所以整個程序中, 任何其他事務都不能對該行資料增加排他鎖; 所以, 可重復讀能夠解決不可重復讀的讀現象)
事務1更新某行記錄時, 事務2不能對這行記錄做更新, 直到事務1結束 (事務一在更新資料的時候, 會對該行資料增加排他鎖, 知道事務結束才會釋放鎖, 所以, 在事務二沒有提交之前, 事務一都能不對資料增加共享鎖進行資料的讀取; 所以, 提交讀可以解決臟讀的現象)
4.可序列化 (Serializable)
- 定義
是最高的隔離級別, 前面三種隔離級別都無法解決的幻讀, 在可序列化的隔離級別中可以解決
- 資料庫鎖情況
事務在讀取資料時, 必須先對其加表級共享鎖, 直到事務結束才釋放
事務在更新資料時, 必須先對其加表級排他鎖, 直到事務結束才釋放
- 現象解釋
事務1正在讀取A表中的記錄時, 則事務2也能讀取A表, 但不能對A表做更新、新增、洗掉, 直到事務1結束 (因為事務一對表增加了表級共享鎖, 其他事務只能增加共享鎖讀取資料, 不能進行其他任何操作)
事務1正在更新A表中的記錄時, 則事務2不能讀取A表的任意記錄, 更不可能對A表做更新、新增、洗掉, 直到事務1結束 (事務一對表增加了表級排他鎖, 其他事務不能對表增加共享鎖或排他鎖, 也就無法進行任何操作)
- 序列化事務產生的效果
- 無法讀取其他事務已經修改單位提交的記錄
- 在當前事務完成之前, 其他事務不能修改當前事務已經讀取的記錄
- 在當前事務完成之前, 其他事務插入的新記錄, 其索引鍵值不能在當前事務的任何陳述句所讀取的索引鍵范圍中
5.隔離級別的選擇
四種事務隔離級別從隔離程度上越來越高, 但同時在并發性上也就越來越低; 之所以有這么幾種隔離級別, 就是為了方便開發人員在開發程序中根據業務需要選擇最合適的隔離級別
四.修改事務隔離級別
1.查看當前事務隔離級別
- 可以通過模糊匹配變數名
show variables like "%tx_isolation";

- 直接查看變數 tx_isolation
select @@tx_isolation;

- 也可以通過以下陳述句查看
select @@global.tx_isolation; # 查看全域事務隔離級別
select @@session.tx_isolation; # 查看當前會話事務隔離級別

ps : 在MySQL 8.0.3 中, tx_isolation 變數被 transaction_isolation 變數替換了; 在 MySQL 8.0.3 版本中查詢事務隔離級別, 只要把上述查詢陳述句中的 tx_isolation 變數替換成 transaction_isolation 變數即可
2.修改事務隔離級別
Mysql提供了 set transaction 陳述句來改變單個會話或者全域會話的事務隔離級別
set [session|global] transaction isolation level
[read ununcommitted|read committed|repeatable read|serializable]
- session : 表示修改的事務隔離級別將應用于當前 session(當前 cmd 視窗) 內的所有事務
- global : 表示修改的事務隔離級別將應用于所有 session (全域) 中的所有事務, 且當前已經存在的 session 不受影響
- 如果省略 session 和 global, 則表示修改的事務隔離級別將應用于當前 session 內的下一個還未開始的事務
3.用戶權限問題
任何用戶都能改變會話的事務隔離級別, 但是只有擁有 super 權限的用戶才能改變全域的事務隔離級別
- 驗證修改全域事務隔離級別, 當前會話不受影響
select @@global.tx_isolation; # 查看全域事務隔離級別
select @@session.tx_isolation; # 查看當前會話事務隔離級別
set global transaction isolation level read committde;
# 修改全域事務隔離級別

- 可以通過直接修改 tx_isolation 變數來修改當前 session 的事務隔離級別
set tx_isolation="read-committed";
select @@session.tx_isolation;

---end---
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/265324.html
標籤:其他
上一篇:open
下一篇:MySql-Day-01
