數據庫在并發訪問時,不同隔離級別下臟讀幻讀問題

數據庫隔離級別并非安裝后就固定,絕大多數主流數據庫(如MySQL、PostgreSQL、SQL Server)都支持動態調整和運行中自定義,具體調整范圍可分為全局、會話和語句三個層級。

  1. 全局級別調整:修改數據庫配置文件(如MySQL的my.cnf)并重啟服務,會影響所有新創建的會話,屬于長期生效的配置。
  2. 會話級別調整:在當前數據庫連接中執行特定SQL命令(如MySQL的SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED),僅對當前會話生效,關閉連接后失效,適合臨時切換隔離級別。
  3. 語句級別調整:部分數據庫支持為單個事務語句指定隔離級別(如SQL Server的SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; BEGIN TRANSACTION; ... COMMIT;),僅對該次事務生效,靈活性最高。

不同數據庫的具體調整語法略有差異,但核心邏輯均支持動態修改,無需重新安裝數據庫。

要模擬MySQL 5.7中事務并發的臟讀、不可重復讀、幻讀,需先創建測試表和基礎數據,再通過「兩個會話模擬并發事務」,結合不同隔離級別驗證問題及解決辦法。以下是完整步驟:

一、基礎準備:創建表與初始化數據

1. 創建測試表(用戶余額表)
-- 建表:id(主鍵)、user_id(用戶ID)、balance(余額)
CREATE TABLE `user_balance` (`id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',`user_id` INT(11) NOT NULL COMMENT '用戶ID',`balance` DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT '賬戶余額',PRIMARY KEY (`id`),UNIQUE KEY `idx_user_id` (`user_id`) -- 唯一索引,確保用戶ID不重復
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用戶余額表';
2. 插入初始化數據
-- 插入1條測試數據:用戶ID=1001,初始余額1000元
INSERT INTO user_balance (user_id, balance) VALUES (1001, 1000.00);-- 驗證數據
SELECT * FROM user_balance WHERE user_id = 1001;

二、核心概念:MySQL隔離級別與并發問題

MySQL 5.7默認隔離級別是 REPEATABLE READ(可重復讀),不同隔離級別對并發問題的抑制能力不同:

隔離級別臟讀不可重復讀幻讀
READ UNCOMMITTED(讀未提交)允許允許允許
READ COMMITTED(讀已提交)禁止允許允許
REPEATABLE READ(可重復讀)禁止禁止禁止(InnoDB通過MVCC實現)
SERIALIZABLE(串行化)禁止禁止禁止

模擬規則:需打開「兩個MySQL會話」(如Navicat的兩個查詢窗口、CMD的兩個mysql連接),分別執行「事務A」和「事務B」,按步驟操作。

三、場景1:臟讀(Dirty Read)

什么是臟讀?

事務A讀取了事務B未提交的修改數據,若事務B后續回滾,事務A讀取的就是“無效臟數據”。

1. 模擬臟讀(需先設置隔離級別為「READ UNCOMMITTED」)
步驟1:兩個會話均設置隔離級別
-- 會話1、會話2均執行:設置當前會話隔離級別為讀未提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
步驟2:開啟事務并執行操作(按順序執行)
步驟會話1(事務A:查詢用戶余額)會話2(事務B:修改用戶余額但不提交)
1BEGIN;(開啟事務)
SELECT balance FROM user_balance WHERE user_id=1001;
– 結果:1000.00
-
2-BEGIN;(開啟事務)
UPDATE user_balance SET balance=balance-200 WHERE user_id=1001;
– 不執行COMMIT(事務未提交)
3SELECT balance FROM user_balance WHERE user_id=1001;
– 結果:800.00(讀取到事務B未提交的修改,臟讀發生!)
-
4-ROLLBACK;(事務B回滾,修改作廢)
5SELECT balance FROM user_balance WHERE user_id=1001;
– 結果:1000.00(數據恢復,驗證步驟3讀的是臟數據)
-
6COMMIT;(關閉事務A)-
2. 解決臟讀:提升隔離級別至「READ COMMITTED」及以上
-- 兩個會話均設置隔離級別為讀已提交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;-- 重復上述步驟2,會發現:步驟3中會話1讀取的余額仍為1000.00(事務B未提交的修改不可見),臟讀被禁止。

四、場景2:不可重復讀(Non-Repeatable Read)

什么是不可重復讀?

事務A在同一事務內多次讀取同一數據,若事務B在兩次讀取間「提交了修改」,則事務A兩次讀取的結果不一致。

1. 模擬不可重復讀(需設置隔離級別為「READ COMMITTED」)
步驟1:兩個會話均設置隔離級別
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
步驟2:開啟事務并執行操作(按順序執行)
步驟會話1(事務A:多次查詢同一用戶余額)會話2(事務B:修改并提交用戶余額)
1BEGIN;(開啟事務)
SELECT balance FROM user_balance WHERE user_id=1001;
– 結果:1000.00
-
2-BEGIN;(開啟事務)
UPDATE user_balance SET balance=balance-200 WHERE user_id=1001;
COMMIT;(提交事務,修改生效)
3SELECT balance FROM user_balance WHERE user_id=1001;
– 結果:800.00(與步驟1結果不一致,不可重復讀發生!)
-
4COMMIT;(關閉事務A)-
2. 解決不可重復讀:提升隔離級別至「REPEATABLE READ」及以上
-- 兩個會話均設置隔離級別為可重復讀(MySQL默認級別)
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;-- 重復上述步驟2,會發現:步驟3中會話1讀取的余額仍為1000.00(事務B提交的修改對事務A不可見),不可重復讀被禁止。

五、場景3:幻讀(Phantom Read)

什么是幻讀?

事務A在同一事務內按同一條件多次查詢,若事務B在兩次查詢間「提交了新數據插入/刪除」,則事務A兩次查詢的「結果行數不一致」(像出現了“幻覺”)。

1. 模擬幻讀(需設置隔離級別為「READ COMMITTED」,MySQL默認的REPEATABLE READ已禁止幻讀)
步驟1:兩個會話均設置隔離級別
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
步驟2:開啟事務并執行操作(按順序執行)
步驟會話1(事務A:按條件多次查詢用戶)會話2(事務B:插入新用戶并提交)
1BEGIN;(開啟事務)
SELECT COUNT(*) FROM user_balance WHERE user_id > 1000;
– 結果:1(僅user_id=1001)
-
2-BEGIN;(開啟事務)
INSERT INTO user_balance (user_id, balance) VALUES (1002, 1500.00);
COMMIT;(提交事務,新用戶插入生效)
3SELECT COUNT(*) FROM user_balance WHERE user_id > 1000;
– 結果:2(新增了user_id=1002,行數不一致,幻讀發生!)
-
4COMMIT;(關閉事務A)-
2. 解決幻讀:使用「REPEATABLE READ」或「SERIALIZABLE」隔離級別
-- 兩個會話均設置隔離級別為可重復讀(MySQL默認)
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;-- 重復上述步驟2,會發現:步驟3中會話1查詢的COUNT(*)仍為1(事務B插入的新數據對事務A不可見),幻讀被禁止。-- 若用SERIALIZABLE級別:會話2插入數據時會被阻塞,直到會話1提交事務,徹底避免幻讀(但性能損耗大)。

六、關鍵總結

  1. 問題本質:并發事務對數據的「修改/插入」與「讀取」的時序沖突,隔離級別通過控制數據可見性解決沖突。
  2. MySQL默認隔離級別:REPEATABLE READ,已能禁止臟讀、不可重復讀、幻讀(InnoDB的MVCC機制實現),兼顧性能與一致性。
  3. 語法記憶
    • 查看當前會話隔離級別:SELECT @@tx_isolation;(MySQL 5.7)/ SELECT @@transaction_isolation;(MySQL 8.0+)
    • 設置會話隔離級別:SET SESSION TRANSACTION ISOLATION LEVEL 級別名稱;
    • 開啟/提交/回滾事務:BEGIN; / COMMIT; / ROLLBACK;

在 MySQL 5.7 配置文件中,用于設置事務默認隔離級別的參數是 transaction_isolation(或舊版兼容參數 tx_isolation,兩者功能一致,推薦使用 transaction_isolation)。

1. 參數說明

  • 核心作用:定義 MySQL 實例啟動后,所有新創建會話的默認事務隔離級別,無需在每個會話中手動設置。
  • 參數值(對應 4 種隔離級別)
    • READ-UNCOMMITTED:讀未提交(可能出現臟讀、不可重復讀、幻讀)
    • READ-COMMITTED:讀已提交(避免臟讀,可能出現不可重復讀、幻讀)
    • REPEATABLE-READ:可重復讀(MySQL 5.7 默認級別,避免臟讀、不可重復讀,通過 MVCC 減少幻讀)
    • SERIALIZABLE:串行化(完全避免三種問題,性能最低)

2. 配置方式(永久生效)

  1. 找到 MySQL 5.7 的配置文件(路徑因系統而異):
    • Linux:通常為 /etc/my.cnf/etc/mysql/my.cnf
    • Windows:通常為 MySQL安裝目錄/my.ini
  2. [mysqld] 模塊下添加/修改參數:
    [mysqld]
    # 設置默認事務隔離級別為可重復讀(MySQL 5.7 默認值,可根據需求修改)
    transaction_isolation = REPEATABLE-READ
    
  3. 重啟 MySQL 服務使配置生效:
    • Linux:systemctl restart mysqld
    • Windows:在“服務”中重啟“MySQL”服務

3. 臨時生效方式(當前會話/全局)

若無需永久修改,可通過 SQL 語句臨時設置(重啟服務后失效):

  • 當前會話生效
    SET SESSION transaction_isolation = 'READ-COMMITTED';
    
  • 全局生效(對新會話生效,已存在會話不影響)
    SET GLOBAL transaction_isolation = 'SERIALIZABLE';
    

4. 驗證隔離級別

通過以下 SQL 查看當前生效的隔離級別:

-- 查看當前會話的隔離級別
SELECT @@session.transaction_isolation;-- 查看全局的隔離級別
SELECT @@global.transaction_isolation;

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

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

相關文章

JVM從入門到實戰:從字節碼組成、類生命周期到雙親委派及打破雙親委派機制

摘要:本文圍繞 Java 字節碼與類加載機制展開,詳解字節碼文件組成、類的生命周期,介紹類加載器分類、雙親委派機制及打破該機制的方式,還闡述了線程上下文類加載器與 SPI 機制在 JDBC 驅動加載中的應用,幫助深入理解 Ja…

多源最短路(Floyd算法

多源最短路簡介 多源最短路算法用于解決圖中任意兩節點間最短路徑的問題,廣泛應用于交通網絡、社交關系分析、路由優化等場景。與單源最短路(如Dijkstra)不同,它一次性計算所有節點對的最短距離,適合需要全局路徑規劃的…

【攻防實戰】記一次攻防實戰全流程

那天我向眾神祈禱,最后回答我的卻只有掙扎十年依舊不甘的自己!成功究竟是饋贈還是償還。 前言 網絡安全技術學習,承認??的弱點不是丑事,只有對原理了然于?,才能突破更多的限制。 擁有快速學習能力的安全研究員&…

Anaconda配置環境變量和鏡像

Anaconda配置環境變量和鏡像 下載失敗就是開了梯子 Anaconda 作用:包管理(集中,有序)和環境管理(版本切換)使用conda命令對虛擬環境創建、刪除自帶python解釋器pip(python自帶的包管理工具&…

給定單詞倒排

實現代碼&#xff1a;public static void main(String[] args) {Scanner scanner new Scanner(System.in);// 輸入的字符串String input scanner.nextLine();// 存儲單詞List<String> words new ArrayList<>();// 存儲當前單詞StringBuilder currentWord new S…

IO進程——進程引入、進程函數接口

一、引入1、進程&程序1.1 程序編譯好的可執行的文件存放在磁盤上的指令和數據的有序集合&#xff08;文件&#xff09;程序是靜態的&#xff0c;沒有任何執行的概念1.2 進程一個獨立的可調度的任務執行一個程序所分配的資源的總稱進程是程序執行的一次過程進程是動態的&…

周末游戲推薦:安卓端俄羅斯方塊,經典與創新的結合

前段時間&#xff0c;每到周末我都會給大家推薦一些離線的經典游戲&#xff0c;原本打算將這個傳統一直延續下去。然而&#xff0c;我實在找不到足夠好用且無廣告的游戲了。有些游戲剛開始用的時候還不錯&#xff0c;但用著用著就開始頻繁彈出廣告&#xff0c;這讓我實在不敢向…

《用 Scikit-learn 構建 SVM 分類模型:從原理到實戰的全流程解析》

《用 Scikit-learn 構建 SVM 分類模型:從原理到實戰的全流程解析》 一、引言:為什么選擇 SVM? 在機器學習的眾多算法中,支持向量機(SVM)以其強大的分類能力和良好的泛化性能,在文本分類、人臉識別、醫學診斷等領域廣泛應用。尤其在中小規模數據集上,SVM 往往能提供比…

一文學會CMakeLists.txt: CMake現代C++跨平臺工程化實戰

你能學到什么&#xff1f;朋友們好久不見&#xff0c;我是alibli&#xff0c;好久沒有更新博客了。今天本人將通過構造一個實際的虛擬小項目&#xff0c;來讓你徹底掌握CMake跨平臺工程構建&#xff0c;學會CMakeLists.txt語法。該項目實現了一個簡單的平方、立方的計算程序&am…

高并發場景下限流算法實踐與性能優化指南

高并發場景下限流算法實踐與性能優化指南 在大規模并發訪問環境中&#xff0c;合理的限流策略能保護后端服務穩定運行&#xff0c;避免系統因瞬時高并發導致資源耗盡或崩潰。本文將從原理出發&#xff0c;深入解析幾種主流限流算法&#xff0c;并結合Java和Redis給出完整可運行…

Vue3應用執行流程詳解

精確化的完整執行流程 (以 Vite Vue3 SPA 為例)整個過程可以分為兩部分&#xff1a;首次訪問的“冷啟動”和后續的Vue應用接管。第一部分&#xff1a;首次訪問與頁面加載客戶端&#xff1a;發送請求用戶打開瀏覽器&#xff0c;輸入 URL&#xff08;如 http://localhost:5173&a…

Redis 持久化與高可用實踐(RDB / AOF / Sentinel / Cluster 全解析)

這篇是我把幾套生產環境踩坑與復盤整理成的一份“從 0 到 1 長期可維護”的實踐文。目標是&#xff1a;明確策略、給出默認可用的配置模板、把常見坑一次講透。 適用場景&#xff1a;新項目選型、老項目穩定性加固、從單機遷移到 HA/Cluster、應對數據安全與故障切換要求。目錄…

Linux內核的PER_CPU機制

參考書《Linux內核模塊開發技術指南》 1.原理 在多核CPU的情況下&#xff0c;為了提高CPU并發執行的效率&#xff0c;對于某些不是必須要在核間進行同步訪問的資源&#xff0c;可以為每一個CPU創建一個副本&#xff0c;讓每個CPU都訪問自身的數據副本&#xff0c;而不是通過加鎖…

VSCode 的百度 AI編程插件

VSCode 的百度 AI編程插件主要是 Baidu Comate&#xff08;文心快碼&#xff09;&#xff0c;這是一款基于文心大模型的新一代編碼輔助工具&#xff0c;旨在提升開發者的編碼效率&#xff0c;讓寫代碼變得更簡單。以下是關于 Baidu Comate 的詳細介紹&#xff1a; 一、功能特點…

阿里云監控使用

阿里云的云監控服務&#xff08;CloudMonitor&#xff09;是一款簡單易用、功能強大的監控工具&#xff0c;主要用來幫助用戶實時監控阿里云上的各種資源&#xff08;比如服務器、數據庫、網絡等&#xff09;&#xff0c;并在出現問題時及時發出警報&#xff0c;確保業務穩定運…

嵌入式C語言-關鍵字typedef

定義和作用 typedef是C/C中的一個關鍵字&#xff0c;作用是為現有的數據類型&#xff08;int 、char 、flaot等&#xff09;創建新的別名&#xff0c;其目的是為了方便閱讀和理解代碼。 用法 typedef 原有類型名 新類型名;基本類型創建別名 typedef unsigned char uint8_t; typ…

【混合開發】【大前端++】Vue節點優化Dome之單節點輪播圖片播放視頻二

動圖更精彩 背景 Vue作為大前端開發頁面交互&#xff0c;在數字屏&#xff0c;智慧大屏等大屏幕開發過程中&#xff0c;輪播效果作為豐富的展示組件經常作為首選。但也因為這個組件的交互體驗很好&#xff0c;于是各種單點組件增加到輪播效果里。經過業務的擴展&#xff0c;人…

前端開發核心技術與工具全解析:從構建工具到實時通信

覺得主包文章可以的,可以點個小愛心喲&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 主頁:一位搞嵌入式的 genius-CSDN博客 系列文章專欄: https://blog.csdn.net/m0_73589512/category_13028539.html 前端開發核心技術與工具全解…

GPT 系列論文 gpt3-4 175B參數 + few-shot + 多模態輸入 + RLHF + system

GPT&#xff0c;GPT-2&#xff0c;GPT-3 論文精讀【論文精讀】 GPT-4論文精讀 從1750億參數的文本預言家&#xff0c;到多模態的通用天才&#xff0c;OpenAI用兩次震撼世界的發布&#xff0c;重新定義了人工智能的可能性邊界。這份筆記將帶你深入GPT-3和GPT-4的核心突破&#…

.gitignore文件的作用及用法

目錄 ??.gitignore 文件的作用?? ??.gitignore 的基本語法?? ??Python 項目的 .gitignore 示例?? ??如何使用 .gitignore?? ??1. 創建 .gitignore 文件?? ??2. 編輯 .gitignore?? ??3. 檢查 Git 狀態?? ??常見問題?? ??Q1&#xff…