MySQL事務篇-事務概念、并發事務問題、隔離級別

事務

事務是一組不可分割的操作集合,這些操作要么同時成功提交,要么同時失敗回滾。

acid事物的四大特性

原子性

最小工作單元,要么同時成功,要么同時失敗。

例如A轉賬300給B,A賬戶-300與B賬戶+300必須滿足操作原子性,避免出現A已轉賬但B未收到的一致性問題。

一致性

事務操作的起點和終點必須是從一個一致性狀態到另一個一致性狀態,也就是數據庫的數據變化必須符合預定義期望變化。(不會出現一個數據庫修改成功、一個失敗的情況)

例如在轉賬案例中事務開始時的賬戶總額等于事務結束時的賬戶金額。(并不是一定相等,數據變化符合業務預定義期望即可)

隔離性

并發的事務是相互隔離的。

例如多個并發轉賬事務,每個轉賬操作的數據是相互獨立的,不會出現數據混亂的情況。

持久性

一旦事務提交,其結果就是永久的,不會因系統崩潰丟失。

事務提交后會將數據持久化到硬盤,例如在裝張案例中,變更后賬戶數據持久化在硬盤,數據庫崩潰依然被保留。

并發事務問題

臟讀

事務A讀取到事務B未提交的修改。

不可重復讀

同一事務內多次讀取同一數據時因為其他事物在此期間提交了數據修改導致結果不同。

幻讀

同一事務內對一張表的查詢結果集不同,因為其他事務在此期間插入刪除了數據。

select * 結果集行數不同。

select count()/sum() 等聚合函數,查詢內容可能不同。

例如,事務A查詢name=張三不存在,事務B插入張三,事務A按照張三不存在的業務邏輯插入張三但無法插入。

隔離級別

讀未提交(RU)

允許事務讀取其他事物未提交的修改(臟讀)。

并發性能最高。

讀已提交(RC)

不允許事務讀取其他事物未提交的修改(臟讀)。

無法避免不可重復讀現象。

可重復讀(RR)

不會出現臟讀和不可重復讀問題。

無法避免幻讀問題。

MySQL默認隔離級別。

串行化(S)

完全避免所有并發問題。

并發性能最低。

如何選擇隔離級別

隔離級別越高,并發性能越低。

  • 讀未提交(RU):僅適用對數據準確性要求極低,并發性能要求極高的場景,如監控數據,日志采集,瞬時數據不影響整體的場景,但實際實際生產環境下中還是極少使用,規避臟讀風險。

  • 讀已提交(RC):適用大部分普通業務場景,也是大部分數據庫的默認隔離級別。例如用戶信息頁,用戶A修改提交后,用戶B刷新就能看到用戶A提交的修改內容,但不會看到用戶A未提交的內容。

    RC下不可重復讀問題:

    🛒 場景一:庫存扣減(并發搶購)

    • 業務邏輯: 用戶下單時,需要檢查并扣減商品庫存(例如商品A,初始庫存10件)。

    • 事務A (用戶1下單):

      1. BEGIN; (RC隔離級別)

      2. SELECT stock FROM products WHERE id = 'A'; // 返回 10 (庫存充足)

      3. (基于查詢結果10,決定繼續下單邏輯... 生成訂單、計算價格等,耗時幾毫秒/秒)

    • 事務B (用戶2下單): (幾乎與事務A同時發生)

      1. BEGIN; (RC隔離級別)

      2. SELECT stock FROM products WHERE id = 'A'; // 也返回 10 (庫存充足)

      3. UPDATE products SET stock = stock - 1 WHERE id = 'A'; // 扣減1件,庫存變為9

      4. COMMIT; // 用戶2下單成功,庫存更新為9并生效

    • 事務A 繼續執行:

      1. (執行完其他邏輯后)

      2. UPDATE products SET stock = stock - 1 WHERE id = 'A'; // 此時基于 *當前已提交數據* (stock=9) 扣減,庫存變為8

      3. COMMIT; // 用戶1下單成功

    • 問題:

      • 兩個用戶都成功下單購買了商品A。

      • 最終庫存變為 8,這符合物理扣減。

    • 不可重復讀在哪里?

      • 事務A 在步驟2讀取 stock=10

      • 在它執行后續邏輯時,事務B 修改并提交了庫存(變為9)。

      • 當事務A 執行更新操作(步驟2.2)時,它沒有基于自己最初讀到的10去減1,而是基于最新已提交值9去減1。雖然最終庫存正確(8),但事務A在邏輯判斷(庫存是否充足)后,執行更新操作時依賴的數據(庫存值)已經發生了變化(10 -> 9)。這就是一次“不可重復讀”(在同一個事務A內,如果它再次執行SELECT stock...,結果會是9,而不是最初的10)。

    • 潛在風險:

      • 超賣風險: 如果初始庫存只有1件,多個事務都讀到1(認為充足),然后都去扣減1(事務B扣成0并提交,事務A再基于0扣減就會變成-1)。這就是經典的并發超賣問題!雖然RC下避免了臟讀(不會讀到事務B未提交的扣減),但因為不可重復讀,兩個事務都基于“過時”的充足判斷進行了扣減,導致庫存為負。解決超賣通常需要額外的并發控制(如樂觀鎖、悲觀鎖、Redis分布式鎖等),而不僅僅是依賴隔離級別。

    🕒 場景二:預約系統(時間段占用檢查)

    • 業務邏輯: 用戶預約某個資源(如會議室A在10:00-11:00時段)。

    • 事務A (用戶1預約):

      1. BEGIN; (RC隔離級別)

      2. SELECT COUNT(*) FROM bookings WHERE room = 'A' AND start_time < '11:00' AND end_time > '10:00'; // 返回 0 (表示10:00-11:00空閑)

      3. (用戶1填寫預約信息,點擊確認... 耗時幾秒)

    • 事務B (用戶2預約): (幾乎與事務A同時發生,且操作更快)

      1. BEGIN; (RC隔離級別)

      2. SELECT ... // 同樣返回0 (空閑)

      3. INSERT INTO bookings (room, start_time, end_time, user) VALUES ('A', '10:00', '11:00', 'user2'); // 插入預約記錄

      4. COMMIT; // 用戶2預約成功

    • 事務A 繼續執行:

      1. (用戶1點擊確認)

      2. INSERT INTO bookings (room, start_time, end_time, user) VALUES ('A', '10:00', '11:00', 'user1'); // 嘗試插入

      3. (可能成功也可能失敗,取決于唯一性約束)

      4. COMMIT;

    • 問題:

      • 事務A和事務B都檢查了同一時間段,都認為它是空閑的(SELECT返回0)。

      • 事務B更快地插入記錄并提交。

      • 事務A隨后也嘗試插入記錄。

    • 不可重復讀在哪里?

      • 事務A在步驟2執行SELECT查詢,得知會議室A在10:00-11:00空閑。

      • 在它執行插入操作之前,事務B已經插入并提交了占用該時間段的記錄。

      • 當事務A執行插入操作時,它所依賴的“空閑”狀態(SELECT的結果)已經不再成立(因為事務B的插入已提交)。事務A在邏輯判斷(是否空閑)后,執行插入操作時依賴的數據狀態(時間段是否被占用)已經發生了變化。如果表上有(room, start_time, end_time)的唯一約束,事務A的插入會失敗(主鍵/唯一鍵沖突)。如果沒有唯一約束,則會產生雙重預訂

    • 潛在風險:

      • 雙重預訂: 最嚴重的后果!同一個時間段被預約給了兩個用戶,導致沖突和用戶投訴。解決雙重預訂通常需要更嚴格的并發控制,如對目標時間段加行鎖(SELECT FOR UPDATE)或使用樂觀鎖(版本號)。

  • 可重復讀(RR):適用同一事務內涉及一個以上對同一數據的查詢,業務要求不能使兩次查詢結果不一致。

    幻讀問題典型案例

    假設存在一張 goods 表,存儲商品庫存信息,初始數據如下:

    idnamestock
    1手機10
    2電腦5

    現在有兩個并發事務:事務 A 負責查詢并修改庫存小于 10 的商品,事務 B 負責插入一條新的庫存小于 10 的商品記錄。

    步驟 1:事務 A 啟動并首次查詢

    事務 A 開始,執行查詢 “庫存小于 10 的商品”:

    -- 事務 ABEGIN;-- 第一次查詢:查詢庫存 < 10 的商品SELECT * FROM goods WHERE stock < 10;

    此時結果為:

    idnamestock
    2電腦5
    步驟 2:事務 B 插入新數據并提交

    事務 B 啟動,插入一條新商品記錄(庫存 8,符合 stock < 10),并提交事務:

    -- 事務 BBEGIN;-- 插入一條新商品,庫存 8(符合 stock < 10)INSERT INTO goods (name, stock) VALUES ('平板', 8);COMMIT;

    此時表中數據變為:

    idnamestock
    1手機10
    2電腦5
    3平板8
    步驟 3:事務 A 再次查詢并嘗試修改

    事務 A 再次執行相同的查詢:

    -- 事務 A-- 第二次查詢:再次查詢庫存 < 10 的商品SELECT * FROM goods WHERE stock < 10;

    RR 隔離級別下,由于 MVCC 的可重復讀特性,事務 A 第二次查詢的結果仍為:

    idnamestock
    2電腦5

    但此時如果事務 A 嘗試修改 “所有庫存 < 10 的商品”(例如批量增加庫存):

    -- 事務 A-- 嘗試修改所有庫存 < 10 的商品UPDATE goods SET stock = stock + 2 WHERE stock < 10;COMMIT;

    執行后,事務 A 查看最終數據時會發現:新插入的 “平板”(id=3)的庫存也被修改為 10(8+2)。 這就是幻讀:事務 A 兩次查詢都沒看到 “平板”,但修改操作卻影響了它,仿佛數據 “憑空出現” 并被修改。

    • 在RR級別下,不可重復讀場景能被解決,但依然會出現更新操作前判斷失效的情況,update是當前讀會直接讀取最新數據修改,依然會出現同時判斷成功的超賣問題。

    • 場景一:庫存扣減

      RR下的行為:

      1.事務A開始并創建快照,執行SELECT stock...讀取的始終是快照中的庫存值(如10)

      2.事務B開始并執行扣減庫存,此時數據庫中stock值為9

      3.事務A開始執行扣減庫存操作UPDATE stock = stock - 1但會讀取到被修改后的最新數據修改。

      結果:事務AB庫存判斷成功雖然解決了不可重復讀問題但還是會導致超賣

      解決方法:樂觀鎖、悲觀鎖、分布式鎖、庫存判斷加For UPDATE

      <select id="selectStockForUpdate" resultType="com.example.Goods">SELECT id, stock FROM goods WHERE id = #{id} FOR UPDATE ?<!-- 關鍵:對查詢到的行加排他鎖 --></select>
  • 串行化(S):事務串行化執行,適用RR下會出現幻讀且業務不允許的場景及事務必須嚴格按照提交順序執行的場景。

    • 1. 💰 金融核心系統 - 銀行轉賬

      -- 事務A: 檢查A余額≥100 → A-100 → B+100-- 事務B: 檢查B余額≥50  → B-50  → C+50

    風險:事務A先開啟但是在未提交的情況下,事務B開啟并檢測B的余額,業務邏輯上B用戶賬戶余額一定滿足>=50,但是在RC,RR情況下事務A未提交所以事務B可能產生誤判。

    串行化解決方案

    1. 嚴格順序執行

      • 事務A完全執行后,再執行事務B

      • 或事務B完全執行后,再執行事務A

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/93828.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/93828.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/93828.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++高頻知識點(二十三)

文章目錄111. 談談atomic1. 什么是原子操作&#xff1f;2. std::atomic 的基本使用示例&#xff1a;基本使用3. 原子操作方法4. 內存模型與順序一致性112. 引用成員變量是否占空間?1. 引用成員變量的定義2. 內存占用情況1. 成員變量的實際占用2. 類的總大小代碼分析113. C中深…

云存儲的高效安全助手:阿里云國際站 OSS

在這個數據爆炸的時代&#xff0c;數據存儲和管理成為了眾多企業和個人面臨的一大挑戰。想象一下&#xff0c;你是一位視頻博主&#xff0c;隨著粉絲量的增長&#xff0c;視頻素材越來越多&#xff0c;電腦硬盤根本裝不下&#xff0c;每次找素材都要花費大量時間。又或者你是一…

【線性基】P4301 [CQOI2013] 新Nim游戲|省選-

本文涉及知識點 C貪心 位運算、狀態壓縮、枚舉子集匯總 線性基 P4301 [CQOI2013] 新Nim游戲 題目描述 傳統的 Nim 游戲是這樣的&#xff1a;有一些火柴堆&#xff0c;每堆都有若干根火柴&#xff08;不同堆的火柴數量可以不同&#xff09;。兩個游戲者輪流操作&#xff0c;…

[25-cv-09610]Anderson Design Group 版權維權再出擊,12 張涉案圖片及近 50 個注冊版權需重點排查!

Anderson 版權圖案件號&#xff1a;25-cv-09610立案時間&#xff1a;2025年8月13日原告&#xff1a;Anderson Design Group, Inc.代理律所&#xff1a;Keith原告介紹原告是美國的創意設計公司&#xff0c;成立于1993年&#xff0c;簡稱ADG&#xff0c;一家家族企業&#xff0c;…

Mac下載AOSP源代碼

一、前期準備 硬件要求 至少 200GB 可用空間(源碼約 100GB,編譯產物需額外空間),推薦 SSD。 內存 16GB+,避免同步 / 編譯時卡頓。 系統要求 macOS 10.14+(推薦最新版本,兼容性更好) 二、環境配置 AOSP 源碼包含大小寫不同的文件(如 File.java 和 file.java),而 …

Linux之網絡

Linux之網絡兩個模型應用層協議HTTPS傳輸層協議UDPTCP可靠性與效率的兼顧面向字節流TCP異常情況底層實現網絡層協議IP網段劃分子網劃分NAT數據鏈路層協議以太網ARP代理服務器內網穿透五種IO多路復用Reactor模式本文旨在講解tcp-ip協議原理&#xff0c;并不涉及代碼部分&#xf…

MCP(模型上下文協議):是否是 AI 基礎設施中缺失的標準?

每周跟蹤AI熱點新聞動向和震撼發展 想要探索生成式人工智能的前沿進展嗎&#xff1f;訂閱我們的簡報&#xff0c;深入解析最新的技術突破、實際應用案例和未來的趨勢。與全球數同行一同&#xff0c;從行業內部的深度分析和實用指南中受益。不要錯過這個機會&#xff0c;成為AI領…

基于粒子群優化算法優化支持向量機的數據回歸預測 PSO-SVM

一、作品詳細簡介 1.1附件文件夾程序代碼截圖 全部完整源代碼&#xff0c;請在個人首頁置頂文章查看&#xff1a; 學行庫小秘_CSDN博客?編輯https://blog.csdn.net/weixin_47760707?spm1000.2115.3001.5343 1.2各文件夾說明 1.2.1 main.m主函數文件 該代碼實現了使用PSO…

版本更新!FairGuard-Mac加固工具已上線!

FairGuard-Mac加固工具1.0.2版本更新日志&#xff1a;■ 支持 AssetBundle 資源加密;■ 支持 Unity global-metadata 文件加密;AssetBundle &#xff0c;是 Unity 提供的一種資源存儲壓縮包。其中儲存了游戲的資源&#xff0c;如圖片、模型、紋理、音視頻、代碼等文件。AssetBu…

【Linux篇章】穿越數據迷霧:HTTPS構筑網絡安全的量子級護盾,重塑數字信任帝國!

本篇摘要 本篇文章將從https是什么&#xff0c;為什么需要https角度&#xff0c;基于之前學的http[速戳速通HTTP]認識https&#xff0c;介紹什么是加密等&#xff0c;認識加密的兩種方式&#xff1a;對稱加密和非對稱加密&#xff1b;引出五種不同的通信方加密方式外加滲透證書…

數據庫:表和索引結構

表和索引是如何組織和使用的&#xff0c;在很大程度上取決于具體的關系型DBMS&#xff0c;然而它們都依賴于大致相似的結構和原則。索引頁和表頁表行和索引行都被存儲在頁中。頁的大小一般為4kb&#xff0c;這是一個可以滿足大部分需求的大小&#xff0c;也可以是其他大小&…

Java 學習筆記(基礎篇5)

1. 綜合練習(1) 抽獎public class test10 {public static void main(String[] args) {int[] arr {2,588,888,1000,10000};Random r new Random();for (int i 0; i < arr.length; i) {int randomIndex r.nextInt(arr.length);int temp arr[randomIndex];arr[randomIndex…

P1162 填涂顏色(染色法)

P1162 填涂顏色 - 洛谷 #include <bits/stdc.h> using namespace std; #define ll long long const int N 1e7 10; int n; int a[100][100],b[110][110]; int dx[4]{-1,1,0,0}; int dy[4]{0,0,1,-1}; void dfs(int x,int y) {if(x<0 || x>n1 || y<0 || y>n…

Webrtc在項目中承擔的角色

一、簡單劃分 解決方案層:負責對SDK的對接、操作業務邏輯、UI封裝、采集、渲染等,屬于基礎業務邏輯層 會議SDK層:負責對會議業務邏輯的封裝、服務端交互、創會/加會/離會等,屬于會議業務邏輯層 mediasoupclient層: 負責對webrtc封裝,提供會議層面相關接口,屬于webrtc業務…

Servlet上傳文件

這是一個Maven項目tomcat版本&#xff1a;9.0.107pom.xml<project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.apache.…

cocos creator 3.8 - 精品源碼 -《漢中漢:漢字中的字》

cocos creator 3.8 - 精品源碼 - 超級文字大師游戲介紹功能介紹免費體驗下載開發環境游戲截圖免費體驗游戲介紹 《漢中漢&#xff1a;漢字中的字》、找漢字&#xff0c;是一款從文字中的筆畫找出可以組成新漢字的小游戲。比如&#xff1a;“王”字中的筆畫就可以組成&#xff…

手機端的音視頻界面或者圖片文檔界面共享給大屏

手機端的音視頻界面或者圖片文檔界面共享給大屏&#xff0c;可通過無線投屏和有線連接等技術手段實現&#xff0c;以下是具體介紹&#xff1a;無線投屏&#xff1a;AirPlay&#xff1a;這是蘋果公司開發的無線共享協議。蘋果手機可通過上滑或下拉調出控制中心&#xff0c;點擊 …

Linux內存管理系統性總結

Linux內存管理系統性總結 內存管理核心架構圖 #mermaid-svg-hKRdgBBYXZTiost8 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-hKRdgBBYXZTiost8 .error-icon{fill:#552222;}#mermaid-svg-hKRdgBBYXZTiost8 .error-t…

MySQL 運算符實戰:9 道經典練習題解析

MySQL 運算符實戰&#xff1a;9 道經典練習題解析 運算符是 MySQL 查詢的 “靈魂”&#xff0c;靈活運用各類運算符能讓數據篩選更加精準高效。本文通過 9 道實戰練習題&#xff0c;詳解邏輯運算符、比較運算符及模糊匹配的用法&#xff0c;幫你快速掌握運算符的核心應用場景。…

【R語言】更換電腦后,如何在新設備上快速下載原來設備的 R 包?

【R語言】更換電腦后&#xff0c;如何在新設備上快速下載原來設備的 R 包&#xff1f; 在日常使用 R 進行數據分析時&#xff0c;我們往往會安裝很多包&#xff08;packages&#xff09;&#xff0c;一旦更換電腦&#xff0c;手動一個一個重新安裝會非常麻煩。本文介紹一種簡單…