文章目錄
- 事務隔離性理論
- 理解隔離性
- 隔離級別
- 事務隔離級別的設置和查看
- 事務隔離級別
- 讀未提交
- 讀提交(不可重復讀)

事務隔離性理論
- 理解隔離性
MySQL服務可能會同時被多個客戶端進程(線程)訪問,訪問的方式以事務方式進行 - 一個事務可能由多條SQL構成,也就意味著,任何一個事務,都有執行前,執行中,執行后的階段。而所謂的原子性,其實就是讓用戶層,要么看到執行前,要么看到執行后。執行中出現問題,可以隨時回滾。所以單個事務,對用戶表現出來的特性,就是原子性。
- 但,畢竟所有事務都要有個執行過程,那么在多個事務各自執行多個SQL的時候,就還是有可能會出現互相影響的情況。比如:多個事務同時訪問同一張表,甚至同一行數據。
- 數據庫中,為了保證事務執行過程中盡量不受干擾,就有了一個重要特征:隔離性
- 數據庫中,允許事務受不同程度的干擾,就有了一種重要特征:隔離級別
理解隔離性
- sql操作都是具有原子性的,update和select,誰先來誰就先跑
- 每一個人都只能看到自己活著時候世界所對應的樣子,所以我們時間線一直在延展的時候,每個人看到的世界都應該是不一樣的,這才符合自然規律,人與人之間具有隔離性,因此讓每一個事務都看到最新的數據是不合理的,而是應該讓每一個事務在他到來時看到他應該看到的數據。這就是隔離性的體現。
- 隔離性具體要隔離到什么程度,我們就有了隔離級別的概念
- 隔離性就是你可以看到你出生后的時間線的內容,不能看到你出生前的內容
- 隔離級別是你試衣服的時候要進試衣間,試鞋子就不用進試衣間
隔離級別
- 讀未提交:在該隔離級別,所有的事務都可以看到其他事務沒有提交的執行結果。(實際公司不會用這種),這種相當于沒有隔離級別
- 讀提交:一個事務commit之后,另一個事務可以看到這個事務的提交結果
- 可重復讀:相當于一個事務做完操作后,另一個事務也做完操作后,兩個事務都關閉后,重新啟動事務才能看到結果,在操作的途中是看不到結果的,類比于兩個小孩在渾濁的水中潛水,一個小孩要確認另一個小孩是否還在潛水要浮上水面才能知道結果,這是MySQL默認的隔離級別,在操作的途中看到的結果是相同的
- 串行化:事務最高的隔離級別,一個mysql執行完成后另一個mysql才能執行,會影響效率
- 隔離,基本都是通過鎖實現的,不同的隔離級別,鎖的使用是不同的
上面四種隔離級別關注的場景都是當有一個人在進行寫的時候另一個人來讀 (讀寫并發),讀讀的場景都用的是串行化,一個任務進行完才能進行下一個任務
事務隔離級別的設置和查看
1. 只影響當前事務的隔離級別,mysql會默認使用session的隔離級別
2. 全局的隔離級別對所有的事務都影響,全局的改了,當前會話的和另一個事務的都會改變(在重新登入后更改)
SELECT @@session.tx_isolation;
--查看會話(當前)全局隔級別(默認用全局的初始化)
set global transaction isolation level READ UNCOMMITTED;
-- 查看
mysql> SELECT @@global.tx_isolation;
--查看全局隔級別
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set, 1 warning (0.00 sec) mysql> SELECT @@session.tx_isolation;
--查看會話(當前)全局隔級別(默認用全局的初始化)
+------------------------+
| @@session.tx_isolation |
+------------------------+
| REPEATABLE-READ |
+------------------------+
1 row in set, 1 warning (0.00 sec) mysql> SELECT @@tx_isolation;
--默認同上,跟上面的一個是同一個意思
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec) --設置
-- 設置當前會話 or 全局隔離級別語法
// transaction 事務
// isolation 隔離
SET [SESSION | GLOBAL] transaction isolation level
// 讀可不可提交,讀可提交,可重復讀,串行化
{READ UNCOMMITTED | READ COMMITTED |
REPEATABLE READ | SERIALIZABLE} --設置當前會話隔離性,另起一個會話,看不多,只影響當前會話
mysql> set session transaction isolation level serializable; -- 串行化
Query OK, 0 rows affected (0.00 sec) mysql> SELECT @@global.tx_isolation; --全局隔離性還是RR
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set, 1 warning (0.00 sec) mysql> SELECT @@session.tx_isolation; --會話隔離性成為串行化
+------------------------+
| @@session.tx_isolation |
+------------------------+
| SERIALIZABLE |
+------------------------+
1 row in set, 1 warning (0.00 sec) mysql> SELECT @@tx_isolation; --同上
+----------------+
| @@tx_isolation |
+----------------+
| SERIALIZABLE |
+----------------+
1 row in set, 1 warning (0.00 sec) --設置全局隔離性,另起一個會話,會被影響
mysql> set global transaction isolation level READ UNCOMMITTED;
Query OK, 0 rows affected (0.00 sec) mysql> SELECT @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| READ-UNCOMMITTED |
+-----------------------+
1 row in set, 1 warning (0.00 sec) mysql> SELECT @@session.tx_isolation;
+------------------------+
| @@session.tx_isolation |
+------------------------+
| READ-UNCOMMITTED |
+------------------------+
1 row in set, 1 warning (0.00 sec)mysql> SELECT @@tx_isolation;
+------------------+
| @@tx_isolation |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set, 1 warning (0.00 sec)-- 注意,如果沒有現象,關閉mysql客戶端,重新連接。
設置當前事務的隔離級別為讀提交
事務隔離級別
讀未提交
- 臟讀:一個事務在執行中,讀到另一個執行中事務的更新(或其他操作)但是未commit的數據,兩個事務并發執行
- 幾乎沒有加鎖,雖然效率高,但是問題太多,嚴重不建議采用
--終端A
-- 設置隔離級別為 讀未提交
mysql> set global transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.00 sec) --重啟客戶端
mysql> select @@tx_isolation;
+------------------+
| @@tx_isolation |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set, 1 warning (0.00 sec)mysql> select * from account;
+----+--------+----------+
| id | name | blance |
+----+--------+----------+
| 1 | 張三 | 100.00 |
| 2 | 李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec) mysql> begin; --開啟事務
Query OK, 0 rows affected (0.00 sec)mysql> update account set blance=123.0 where id=1; --更新指定行
Query OK, 1 row affected (0.05 sec)
Rows matched: 1 Changed: 1 Warnings: 0--沒有commit哦!!!--終端B mysql> begin;
mysql> select * from account;
+----+--------+----------+
| id | name | blance |
+----+--------+----------+
| 1 | 張三 | 123.00 | --讀到終端A更新但是未commit的數據[insert,delete同樣]
| 2 | 李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)
讀提交(不可重復讀)
-- 終端A
mysql> set global transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)
--重啟客戶端
mysql> select * from account; --查看當前數據
+----+--------+----------+
| id | name | blance |
+----+--------+----------+
| 1 | 張三 | 123.00 |
| 2 | 李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec) mysql> begin; --手動開啟事務,同步的開始終端B事務
Query OK, 0 rows affected (0.00 sec) mysql> update account set blance=321.0 where id=1; --更新張三數據
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0 --切換終端到終端B,查看數據。 mysql> commit; --commit提交!
Query OK, 0 rows affected (0.01 sec) --切換終端到終端B,再次查看數據。 --終端B
mysql> begin; --手動開啟事務,和終端A一前一后
Query OK, 0 rows affected (0.00 sec) mysql> select * from account; --終端A commit之前,查看不到
+----+--------+----------+
| id | name | blance |
+----+--------+----------+
| 1 | 張三 | 123.00 | --老的值
| 2 | 李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec) --終端A commit之后,看到了!
--but,此時還在當前事務中,并未commit,那么就造成了,同一個事務內,同樣的讀取,在不同的時間段(依舊還在事務操作中!),讀取到了不同的值,這種現象叫做不可重復讀(non reapeatable read)!!(這個是問題嗎??)
mysql> select *from account;
+----+--------+----------+
| id | name | blance |
+----+--------+----------+
| 1 | 張三 | 321.00 | --新的值
| 2 | 李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)
不可重復讀會出現什么問題呢?
兩個事務都同時啟動,一個事務提交了(關閉了),另一個運行的事務(查詢)看到第一個事務的提交結果是不合理的,兩個事務都應該是原子的
不可重復讀會造成問題嗎?會造成什么后果?
比如說小王要把tom的工資重3200改到4500,而小張負責工資表發放獎品的任務,小張要進行查詢的任務,當事務運行到3000到4000獎品的查詢時,查到了tom,之后小王提交了事務,在4000到5000獎品的查詢時,又查到了tom,這在公司就出現了問題
所以我們不應該讓我們的用戶在實際操作的時候,兩個正在執行的事務一方能夠讀到另一方的提交。所以雖然讀提交比讀未提交隔離級別高,但是我們也不推薦!因為會導致上述的不可重復讀的問題!!