MySQL事務(4種事務隔離級別、臟寫、臟讀、不可重覆讀、幻讀、當前讀、快照讀、MVCC、事務指標監控)

来源:https://www.cnblogs.com/phpphp/p/18062569
-Advertisement-
Play Games

聲明測試表,供文章案例使用 CREATE TABLE `cs` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `num` int(10) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoD ...


聲明測試表,供文章案例使用

CREATE TABLE `cs` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `num` int(10) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

事務的分類

  • 顯示事務:
    • read write:讀寫事務,預設模式,表示當前事務可以讀寫數據。
    • read only:只讀事務,很少用,表示當前事務不能修改數據。
    • with consistent snapshot:一致性快照,在資料庫事務中確保事務在執行過程中能看到一個事務開始時的一致資料庫狀態,避免被其他併發操作影響。
  • 隱式事務:不需要顯示聲明事務相關語句,autocommit是開啟狀態(預設值),每條DML和DDL的SQL語句都是一個獨立的事務。

MySQL事務的4個特性:

  • 原子性(Atomicity):當前事務中的執行結果,要麼全部執行成功,要麼全部執行失敗。
  • 一致性(Consistency):事務執行前後,資料庫從一個合法(指符合業務預期)狀態轉換成另一個一合法狀態。
  • 隔離性(Isolation):多個事務可以併發執行,各個事務之間的操作互相隔離互不幹擾。
  • 持久性(Durability):無論事務提交還是回滾,都會持久化到磁碟中。

自動提交

自動提交(auto commit),指的是SQL語句執行完畢後自動將數據持久化到磁碟(刷盤)中。
顯式的聲明事務,或者聲明set autocommit = 0;都可以關閉自動提交。

savepoint

  • 俗稱保存點,是用於實現部分事務回滾的一種機制,需要確定從哪裡開始回滾,就需要savepoint的標識來定位。
  • 回滾範圍:從保存點開始到事務最後一條SQL,都會被回滾。
  • 適用場景:用於複雜的業務邏輯中,給出靈活可控的後悔藥,降低事務回滾影響範圍。
  • 註意:rollback to之後,不代表事務流程走完,還需要再次commit提交其它未回滾的事務。
  • 用法:
    savepoint 保存點名:創建一個 Savepoint,併為其指定一個名稱。
    rollbackto savepoint 保存點名;:將事務回滾到指定的 Savepoint。
    release savepoint 保存點名;:釋放指定的 Savepoint。
    示例:
start transaction;
insert into cs(num) values(1);
savepoint insert_1;
insert into cs(num) values(2);
savepoint insert_2;
insert into cs(num) values(3);
savepoint insert_3;
insert into cs(num) values(4);
savepoint insert_4;
rollback to insert_2;
commit;
發現1,2數據被插入。

事務的隱式提交

在上一個事務沒提交或回滾時,運行下一個事務,則上一個事務自動提交。

start transaction;
insert into cs(num) values(1);
insert into cs(num) values(2);
start transaction;
insert into cs(num) values(3);
insert into cs(num) values(4);
commit;
成功插入1,2,3,4。

4種隔離級別

  • 讀未提交(Read Uncommitted):最低級別的隔離,事務中的修改即使未提交也能被其他事務看到,可能導致臟讀、不可重覆讀和幻讀問題。
  • 讀已提交(Read Committed):保證一個事務提交後對其他事務可見,避免了臟讀,但可能會導致不可重覆讀和幻讀問題。
  • 可重覆讀(Repeatable Read):保證在同一事務內多次讀取數據時,數據保持一致,避免了不可重覆讀問題,但仍可能出現幻讀。
  • 串列化(Serializable):最高級別的隔離,通過對讀取的數據添加共用鎖或排他鎖來確保事務之間的隔離性,避免了臟讀、不可重覆讀和幻讀問題,但可能會影響併發性能。

表格從上到下,越來越高可用,但是性能越來越低。

隔離級別 是否解決臟讀 是否解決不可重覆讀 是否解決幻讀 是否加鎖
讀未提交
讀已提交
可重覆讀
串列化

查看或設置MySQL隔離級別

  • 查看:select @@transaction_isolation; 或者 show variables like 'transaction_isolation;'
  • 設置:set session transaction_isolation = 'read-uncommitted/read-committed/repeatable-read/serializable';
    註意隔離級別是回話級別的,所以無法set glboal。

MySQL會發生什麼讀?

因為mysql預設隔離級別是可重覆讀(Repeatable Read),所以只會發生幻讀情況,臟讀和可重覆度不會發生,除非改事務隔離級別。

臟寫(不允許發生)

  • 簡介:一個事務修改某些數據時,另一個事務在未提交的情況下也修改了這些數據,引起的導致數據的不一致性。
  • 危害:造成數據在併發情況下嚴重不一致。
  • 演示:試不出來,臟寫這麼嚴重的bug,是不允許發生的情況。

臟讀(讀未提交隔離級別會發生)

  • 簡介:一個事務尚未commit(提交,刷盤,持久化),卻讀取了事務修改後的值,引起數據讀取不准確的情況。
  • 危害:事務還未提交就被讀取了,該事務成功提交還好,要是回滾了,會造成讀取數據不一致的問題。
  • 演示:因為臟讀是讀未提交(Read Uncommitted)才會發生的情況,所以要降低MySQL的隔離級別。
步驟 會話A 會話B 備註
1 set session transaction_isolation = 'read-committed'; set session transaction_isolation = 'read-committed'; 設置事務的隔離級別為讀未提交
2 select @@transaction_isolation; select @@transaction_isolation; 檢查隔離級別是否設置成功
3 select num from cs where id = 20; #20 start transaction;
update cs set num = 20 where id = 40;
會話A num的初始值為20
4 select num from cs where id = 20; #40 / 會話B並未commit,此時會話A中num的值為40,發生臟讀現象
5 / rollback 結束本次事務
6 select num from cs where id = 20; #20 / num恢復為20

不可重覆讀(讀未提交、讀已提交隔離級別會發生)

  • 簡介:在事務A中讀取某些數據,然後在事務B中修改這些數據,此時事務A讀取這些數據還未發生變化,但是事務B提交後,併在事務A在未結束事務的前提下,那些數據發生了變化,不可重覆讀不是禁止讀動作,而是重覆讀數據不一致。
    一句話概括,在同一個事務中,受其它事務提交的影響,讀取同一數據兩次得到的結果不一致的現象。
  • 危害:破壞了事務內數據的準確性,例如事務內的SQL有自增自減的邏輯,如果事務內的初始值受其他事物提交從而發生變化,那麼這是個巨大的問題。
  • 演示:因為不可重覆讀是讀已提交(Read Committed)才會發生的情況,所以要降低MySQL的隔離級別。
步驟 會話A 會話B 備註
1 set session transaction_isolation = 'read-uncommitted'; set session transaction_isolation = 'read-uncommitted'; 設置事務隔離級別為讀已經提交
2 select @@transaction_isolation; select @@transaction_isolation; 檢查隔離級別是否設置成功
3 start transaction; start transaction; 雙方開啟事務
4 select num from cs where id = 20; #20 select num from cs where id = 20; #20 兩個會話中num的值為20
5 update cs set num = 40 where id = 20; select num from cs where id = 20; #20 會話A將數據更新為40,此時會話B查詢的值仍為20
6 commit select num from cs where id = 40; #40 會話A提交事務,會話B仍在事務中,但是得到的值變成了40,發生了不可重覆讀
7 / commit 結束事務

幻讀(讀未提交、讀已提交、可重覆讀隔離級別會發生)

  • 簡介:同一個事務里前後查詢兩次相同範圍的數據,後一次查詢查詢到了前一次看不到的東西,就好像出現了"幻影"一樣。(註意,如果把會話B的insert改為delete導致的數據減少,不算幻讀,算不可重覆讀)。
  • 危害:沒有充分的做好數據隔離,數據一致性存在問題。
  • 演示:mysql 的預設隔離級別為REPEATABLE-READ,所以大概率不用調整隔離級別。
步驟 會話A 會話B 備註
1 select @@transaction_isolation; select @@transaction_isolation; 檢查隔離級別是否是REPEATABLE-READ
2 start transaction; start transaction; 雙方開啟事務
3 select * from cs; select * from cs; 兩個事務查看,都只有id為20的一條數據
4 insert into cs (id,num) values(21,21); select * from cs; 會話B查詢,仍舊只有id為20的一條數據
5 commit / 會話A提交事務
6 / select * from cs; 即使會話A提交了事務,會話B查詢仍舊無法搜索到會話A插入的數據,起始這一步已經幻讀了,但是mysql不表明是幻讀,所以到第7步測試
7 / insert into cs (id,num) values(21,21); 因為會話B select查不到id為21的數據,所以插入id相同的數據,但是報錯1062 - Duplicate entry '21' for key 'PRIMARY'
8 / rollback; 回滾以結束事務流程

如何解決幻讀?

  • 或者使用串列化的隔離級別。在串列化隔離級別下,也會隱式的添加行(X)鎖。
  • 添加間隙鎖,可以避免幻讀。
  • mysql 的預設隔離級別為REPEATABLE-READ,又稱為RR,通過MVCC的機制,如果對數據進行快照讀,正因為讀取的不一定第最新的數據,所以可以防止幻讀(註意不是解決幻讀),如果是當前讀(最近數據),那麼仍舊會發生幻讀現象。

當前讀

當前讀讀的就是數據最新的記錄,需要保證當前讀的數據不能被修改,修改了就不是最新的記錄了(臟寫),因此需要加鎖,select for update、select lock in share mode以及DML(insert、update、delete)獲取的數據都是當前讀的數據。

快照讀

快照讀顧名思義,讀取的就是由MVCC Read View控制的undo log的數據,不加鎖,所以是讀取是非阻塞的。不加鎖的select都屬於快照讀。如果當前事務的隔離級別是串列化,那麼快照讀也變成了當前讀。
舉個例子:常用的navicat,查看一個表,事務提交前的insert或update語句,表格內仍舊顯示的原數據,則用的快照讀。

MVCC

MVCC(Multi-Version Concurrency Control)是 MySQL 中一種實現事務隔離的機制,用於處理資料庫事務併發訪問時可能出現的讀寫衝突。事務的四種隔離級別,就是通過MVCC機制提供的底層支撐。
MVCC三板斧:隱藏欄位、Undo log(存放歷史版本)、Read view(版本控制)

MVCC解決的是讀已提交和可重覆讀級別的併發控制。
因為讀未提交,就算事務未提交,可以直接讀取最新的數據(臟讀),相當於當前讀,那就不分快照讀和當前讀了。
串列化的隔離級別,強制事務串列執行,也不存在快照讀和當前讀的區分,因為讀取的都是事務執行過後的最新數據。

事務各項指標監控

查看 InnoDB 存儲引擎中當前活動的事務信息。

SELECT * FROM information_schema.innodb_trx;

trx_id                         事務的唯一標識符。
trx_state                      事務的狀態,如 RUNNING、LOCK WAIT、ROLLING BACK 等。
trx_started                    事務啟動的時間。
trx_requested_lock_id          請求的鎖的標識符。
trx_wait_started               等待鎖的開始時間。
trx_weight                     事務的權重,用於死鎖檢測。
trx_mysql_thread_id            MySQL 線程 ID。
trx_query                      與事務相關的 SQL 查詢語句。
trx_operation_state            事務內部操作的狀態。
trx_tables_in_use              事務使用的表的數量。
trx_tables_locked              事務鎖定的表的數量。
trx_lock_structs               事務內部使用的鎖結構數量。
trx_lock_memory_bytes          用於事務鎖定的記憶體位元組數。
trx_rows_locked                事務鎖定的行數。
trx_rows_modified              事務修改的行數。
trx_concurrency_tickets        用於事務併發控制的票數。
trx_isolation_level            事務的隔離級別。
trx_unique_checks              是否啟用了唯一性檢查。
trx_foreign_key_checks         是否啟用了外鍵約束檢查。
trx_last_foreign_key_error     最後一個外鍵錯誤信息。
trx_adaptive_hash_latched      是否適應性哈希被鎖定。
trx_adaptive_hash_timeout      適應性哈希鎖定超時次數。
trx_is_foreign_key_with_check  是否用於外鍵約束檢查。
trx_is_foreign_key             是否用於外鍵約束。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一:修改伺服器埠 訪問tomcat主頁的時候,輸入的是localhost:8080,說明tomcat的埠是8080,那麼怎麼修改埠號呢? 我們要先認識配置文件 用瀏覽器打開tomcat下conf子目錄server.xml 這一句的意思是通過8005埠發送大寫的“SHUTDOWN”,會關閉服務 ...
  • 根據微軟發佈的Windows 11操作系統要求,這個版本的系統需要硬體支持受信任的平臺模塊 (TPM) 才能進行安裝和使用,不然就會提示你“這臺電腦無法運行Windows11。這臺電腦不符合安裝此版本的Windows所需的最低系統要求。有關詳細信息,請訪問https://aka.ms/Windows ...
  • proxy_set_header 是 Nginx 配置中的一個重要指令,特別是在使用 Nginx 作為反向代理時。該指令允許你修改由 Nginx 傳遞給代理後端的請求頭。這對於確保後端應用程式能夠接收到正確的客戶端信息(如 IP 地址、主機名等)以及控制緩存行為等場景非常有用。 以下是 proxy_ ...
  • 集群部署方案(2 Master + 3 Worker) Apache DolphinScheduler官網:https://dolphinscheduler.apache.org/zh-cn Apache DolphinScheduler使用文檔:https://dolphinscheduler.a ...
  • 本文分享自華為雲社區《GaussDB(DWS) 集群通信系列一:pooler連接池》,作者:半島里有個小鐵盒。 1.前言 適用版本:【8.1.0(及以上)】 GaussDB(DWS) 為MPP型分散式資料庫,使用Share Nothing架構,數據分散存儲在各個DN節點,而CN不存儲數據,作為接收查 ...
  • 某業務系統將MySQL 8.0.26升級為GreatSQL 8.0.32-24 後,某些特定的SQL語句不能查詢到數據。經測試 MySQL 8.0.32也存在相同的問題 此BUG已在 GreatSQL 8.0.32-25 版本中解決 MySQL 8.0.26版本升級32版本查詢數據為空的跟蹤 接到客 ...
  • 查詢 語法: SELECT 標識選擇哪些列 FROM 標識從哪個表中選擇 去重(Distinct) 在SELECT語句中使用關鍵字DISTINCT去除重覆行 SELECT DISTINCT department_id FROM employees; 過濾(Where) 語法: SELECT 欄位1, ...
  • 本文說明的是MySQL鎖,和操作系統或者編程語言的鎖無關。 概念 作用:在併發情況下讓數據正確的讀寫。 優點:併發情況下對數據讀寫可控,防止出錯。 缺點:降低性能、增加難度。 分類 數據操作類型劃分 讀鎖(共用鎖、S鎖) 寫鎖(排它鎖、獨占鎖、X鎖) 粒度劃分 表級鎖 S鎖、X鎖 意向鎖 自增鎖 元 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...