5、MySQL事务隔离级别详解
事務的隔離性就是指當多個事務同時運行時,各事務之間相互隔離,不可互相干擾。如果事務沒有隔離性,就容易出現臟讀、不可重復讀和幻讀等情況。
為了保證并發時操作數據的正確性,數據庫都會有事務隔離級別的概念。
1) 臟讀
臟讀是指一個事務正在訪問數據,并且對數據進行了修改,但是這種修改還沒有提交到數據庫中,這時,另外一個事務也訪問這個數據,然后使用了這個數據。
2) 不可重復讀
不可重復讀是指在一個事務內,多次讀取同一個數據。
在這個事務還沒有結束時,另外一個事務也訪問了該同一數據。那么,在第一個事務中的兩次讀數據之間,由于第二個事務的修改,那么第一個事務兩次讀到的的數據可能是不一樣的。這樣在一個事務內兩次讀到的數據是不一樣的,因此稱為是不可重復讀。
3) 幻讀
幻讀是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的數據進行了修改,這種修改涉及到表中的全部數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那么,以后就會發生操作第一個事務的用戶發現表中還有沒有修改的數據行,就好象發生了幻覺一樣。
為了解決以上這些問題,標準 SQL 定義了 4 類事務隔離級別,用來指定事務中的哪些數據改變是可見的,哪些數據改變是不可見的。
MySQL 包括的事務隔離級別如下:
- 讀未提交(READ UNCOMITTED)
- 讀提交(READ COMMITTED)
- 可重復讀(REPEATABLE READ)
- 串行化(SERIALIZABLE)
MySQL 事務隔離級別可能產生的問題如下表所示:
MySQL 的事務的隔離級別由低到高分別為 READ UNCOMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE。低級別的隔離級別可以支持更高的并發處理,同時占用的系統資源更少。
下面根據實例來一一闡述它們的概念和聯系。
1. 讀未提交(READ UNCOMITTED,RU)
顧名思義,讀未提交就是可以讀到未提交的內容。
如果一個事務讀取到了另一個未提交事務修改過的數據,那么這種隔離級別就稱之為讀未提交。
在該隔離級別下,所有事務都可以看到其它未提交事務的執行結果。因為它的性能與其他隔離級別相比沒有高多少,所以一般情況下,該隔離級別在實際應用中很少使用。
例 1 主要演示了在讀未提交隔離級別中產生的臟讀現象。
示例 1
Query OK, 0 rows affected (0.57 sec)
mysql> INSERT INTO test.testnum (num) VALUES(1),(2),(3),(4),(5);在 A 窗口中修改事務隔離級別,因為 A 窗口和 B 窗口的事務隔離級別需要保持一致,所以我們使用 SET GLOBAL TRANSACTION 修改全局變量。SQL 語句如下:
mysql> SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; flush privileges;查詢事務隔離級別,SQL 語句和運行結果如下:
mysql> show variables like '%tx_isolation%'\G *************************** 1. row *************************** Variable_name: tx_isolationValue: READ-UNCOMMITTED結果顯示,現在 MySQL 的事務隔離級別為 READ-UNCOMMITTED。
確定事務隔離級別是 READ-UNCOMMITTED 后,開啟一個事務,并使用 UPDATE 語句更新 testnum 數據表,SQL 語句和運行結果如下:
mysql> BEGIN; Query OK, 0 rows affected (0.00 sec) mysql> UPDATE test.testnum SET num=num*2 WHERE num=2; Query OK, 1 row affected (0.02 sec) Rows matched: 1 Changed: 1 Warnings: 0由結果可以看出,A 窗口中的事務讀取到了更新后的數據。
當 MySQL 的事務隔離級別為 READ UNCOMITTED 時,首先分別在 A 窗口和 B 窗口中開啟事務,在 B 窗口中的事務更新但未提交之前, A 窗口中的事務就已經讀取到了更新后的數據。但由于 B 窗口中的事務回滾了,所以 A 事務出現了臟讀現象。
使用讀提交隔離級別可以解決實例中產生的臟讀問題。
2. 讀提交(READ COMMITTED,RC)
顧名思義,讀提交就是只能讀到已經提交了的內容。
如果一個事務只能讀取到另一個已提交事務修改過的數據,并且其它事務每對該數據進行一次修改并提交后,該事務都能查詢得到最新值,那么這種隔離級別就稱之為讀提交。
該隔離級別滿足了隔離的簡單定義:一個事務從開始到提交前所做的任何改變都是不可見的,事務只能讀取到已經提交的事務所做的改變。
這是大多數數據庫系統的默認事務隔離級別(例如 Oracle、SQL Server),但不是 MySQL 默認的。
例 2 演示了在讀提交隔離級別中產生的不可重復讀問題。
示例 2
當 MySQL 的事務隔離級別為 READ COMMITTED 時,首先分別在 A 窗口和 B 窗口中開啟事務,在 B 窗口中的事務更新并提交后,A 窗口中的事務讀取到了更新后的數據。在該過程中,A 窗口中的事務必須要等待 B 窗口中的事務提交后才能讀取到更新后的數據,這樣就解決了臟讀問題。而處于 A 窗口中的事務出現了不同的查詢結果,即不可重復讀現象。
使用可重復讀隔離級別可以解決實例中產生的不可重復讀問題。
3. 可重復讀(REPEATABLE READ,RR)
顧名思義,可重復讀是專門針對不可重復讀這種情況而制定的隔離級別,可以有效的避免不可重復讀。
在一些場景中,一個事務只能讀取到另一個已提交事務修改過的數據,但是第一次讀過某條記錄后,即使其它事務修改了該記錄的值并且提交,之后該事務再讀該條記錄時,讀到的仍是第一次讀到的值,而不是每次都讀到不同的數據。那么這種隔離級別就稱之為可重復讀。
可重復讀是 MySQL 的默認事務隔離級別,它能確保同一事務的多個實例在并發讀取數據時,會看到同樣的數據行。在該隔離級別下,如果有事務正在讀取數據,就不允許有其它事務進行修改操作,這樣就解決了可重復讀問題。
例 3 演示了在可重復讀隔離級別中產生的幻讀問題。
示例 3
使用串行化隔離級別可以解決實例中產生的幻讀問題。
4. 串行化(SERIALIZABLE)
如果一個事務先根據某些條件查詢出一些記錄,之后另一個事務又向表中插入了符合這些條件的記錄,原先的事務再次按照該條件查詢時,能把另一個事務插入的記錄也讀出來。那么這種隔離級別就稱之為串行化。
SERIALIZABLE 是最高的事務隔離級別,主要通過強制事務排序來解決幻讀問題。簡單來說,就是在每個讀取的數據行上加上共享鎖實現,這樣就避免了臟讀、不可重復讀和幻讀等問題。但是該事務隔離級別執行效率低下,且性能開銷也最大,所以一般情況下不推薦使用。
總結
以上是生活随笔為你收集整理的5、MySQL事务隔离级别详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 4、MySQL设置事务自动提交(开启和关
- 下一篇: 6、MySQL查看和修改事务隔离级别