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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...