慣性聚合 高效追蹤和閱讀你感興趣的部落格、新聞、科技資訊
閱讀原文 在慣性聚合中打開

推薦訂閱源

小众软件
小众软件
博客园 - 叶小钗
有赞技术团队
有赞技术团队
大猫的无限游戏
大猫的无限游戏
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
Hugging Face - Blog
Hugging Face - Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
aimingoo的专栏
aimingoo的专栏
Blog — PlanetScale
Blog — PlanetScale
爱范儿
爱范儿
T
Tailwind CSS Blog
Jina AI
Jina AI
量子位
Stack Overflow Blog
Stack Overflow Blog
人人都是产品经理
人人都是产品经理
J
Java Code Geeks
V
Visual Studio Blog
月光博客
月光博客

博客园 - lzhdim

10个不该免费的GitHub神级项目 JavaScript语言全面概述:从历史到现代实践 一张图看懂常见咖啡 C盘空间多出来4GB:谷歌服软 Chrome本地AI大模型可禁用、删除了 96GB显存运行230B大模型!七彩虹灵创K16笔记本评测:160W性能释放 AMD锐龙AI Max+ 395加持全能移动AI工作站 AI PC最强存储搭档!雷克沙NM1090 PRO 8TB固态评测:14400MB/s满速不缩水 C#已经不是当年的C#了——我用它写了个微秒级数据库引擎 EasyTool:轻量全能的 .NET 工具类库 SQL 入门 17:MySQL 数据类型:从字符串到 JSON 的全面解析 原相3955XM+TL3228主控!小米电竞鼠标2全面评测:原生双8K究竟有多强 PCIe 4.0火力全开:闪迪奥丁马仕GX 7100 NVMe SSD上手 超乎预料的千元级电竞主板!七彩虹iGame B850M Ultra-OC V14主板评测 SQL 入门 15:SQL 事务:从 ACID 到四种常见的并发问题 名人 - 我的闪存 C#性能优化技巧 SQL 入门 14:SQL 触发器与事件:自动化数据处理 38个实用的JavaScript 技巧 一款基于 .Net WinForm 开发的节点编辑器,纯 GDI 实现,体积仅 100+Kb Masuit.Tools:这个 C# 工具库 SQL 入门 13:SQL 存储过程与函数:封装逻辑与参数处理 49个 JavaScript 代码快捷技巧,让你在 2026 年成为代码高手 20260503 - 个人小作品更新 - lzhdim SQL 入门 12:SQL 视图:创建、修改与可更新视图 C#如何实现Windows系统桌面截图功能... 6999元AMD新旗舰首测!锐龙9 9950X3D2性能解禁:这颗U根本不是给游戏玩家造的 SQL 入门 11:日期时间格式化、IF、CASE的使用 基于C#的校时类库的实现及使用 - 开源项目研究文章 39g无打孔+原生双8K!雷柏VT0 Air MAX / VT3s Air MAX鼠标评测:轻到飞起还快到极致 WinForm 中控件自适应窗体变化 20260413 - 个人小作品更新 SQL 入门 10:SQL 内置函数:数值、字符串与时间处理 最强麒麟芯+自研风冷 华为Mate80 Pro MAX 风驰版全面评测:涡轮散热封神 性能稳到骨子里 WiFi8核心技术特性与性能分析 2026年最新AMD/Intel桌面CPU排名:多线程、单线程、游戏性能谁才是第一 用DG对C盘进行扩容 - 初学者系列 - 学习者系列 还有比它更强的OEM固态吗!长江存储PC550 1TB评测:不用散热片也能满速的PCIe 5.0 SSD - lzhdim SharpCompress:跨平台的 C# 压缩与解压库 - lzhdim SQL 入门 9:SQL 高级子查询:ANY、EXISTS 与多位置应用 - lzhdim 盘点接私活20个最实用的 .NET 开源项目 - lzhdim C#中加载图片的资源释放 - lzhdim 20260404 - 个人小作品更新 - lzhdim 开启iphone的墙纸玻璃效果 - lzhdim 可能是综合性能最强的PCIe 5.0 SSD!铠侠EXCERIA PRO G2 2TB评测:AIDA64线性写入全程不掉速 SQL 入门 8:SQL 复杂查询:子查询与ALL关键词 - lzhdim 性能最强的锐龙AI 9 H 465轻薄本!华硕无畏Pro16锐龙版2026评测 4盘RAID 0读写超1100MB/s!希捷酷狼Pro 32TB硬盘评测:百万文件快速完成备份 - lzhdim 项目(Project)、项目集(Program)、项目组合(Portfolio) SQL 入门 7:SQL 聚合与分组:函数、GROUP BY 与 ROLLUP
SQL 入門 16:SQL 事務隔離級別與死鎖解析(易懂)
lzhdim · 2026-05-28 · via 博客园 - lzhdim

事務隔離級別是數據庫併發控制的核心,定義了事務之間如何隔離以及一個事務能看到其他事務更改的程度。本文基於 sql_store 數據庫,通過代碼示例詳細講解 MySQL 支持的四種標準事務隔離級別及其影響,結合場景說明隔離級別的作用,並解析死鎖問題及其規避方法,幫助讀者深入理解事務併發管理。

學習內容

1. 事務隔離級別概述

MySQL 支持四種標準事務隔離級別,從低到高分別為:

  • 讀未提交(READ UNCOMMITTED)
    最低隔離級別,事務可讀取其他事務未提交的更改,導致髒讀問題。性能最高,但可能出現髒讀、不可重複讀和幻讀。
  • 讀已提交(READ COMMITTED)
    事務只能讀取已提交的更改,避免髒讀,但仍可能出現不可重複讀和幻讀。許多數據庫(如 Oracle、PostgreSQL)的默認級別。
  • 可重複讀(REPEATABLE READ)
    MySQL InnoDB 的默認隔離級別,通過多版本併發控制(MVCC)和間隙鎖,確保同一事務內多次讀取相同數據結果一致,避免髒讀和不可重複讀,但可能出現幻讀(InnoDB 通過鎖機制部分緩解)。
  • 串行化(SERIALIZABLE)
    最高隔離級別,強制事務串行執行,完全避免髒讀、不可重複讀和幻讀,但性能最低。

隔離級別越高,併發性能越低,但數據一致性越高。ATM 轉賬場景中,合適的隔離級別可確保賬戶餘額更新時不被其他事務干擾。

2. 查看與設置隔離級別

通過 SHOW VARIABLES LIKE 'transaction_isolation' 查看當前隔離級別,默認顯示 REPEATABLE-READ。可通過以下語句設置隔離級別:

  • SET TRANSACTION ISOLATION LEVEL <級別>:影響下一個事務。
  • SET SESSION TRANSACTION ISOLATION LEVEL <級別>:影響當前會話。
  • SET GLOBAL TRANSACTION ISOLATION LEVEL <級別>:影響全局新會話。

3. 併發問題與隔離級別

不同隔離級別對髒讀、不可重複讀和幻讀的控制能力不同:

  • 髒讀:讀取未提交數據,可能導致錯誤決策。
  • 不可重複讀:同一事務內多次查詢結果不一致,因其他事務提交了更改。
  • 幻讀:同一事務內查詢範圍行數變化,因其他事務插入或刪除行。

4. 死鎖

死鎖是併發事務中兩個或多個事務互相等待對方釋放資源,導致無法繼續執行。MySQL 會檢測死鎖並終止一個事務,報錯提示。減少死鎖需保持一致的資源訪問順序或縮短事務長度。

示例代碼與講解

1. 查看隔離級別

SHOW VARIABLES LIKE 'transaction_isolation';

顯示當前隔離級別,默認值為 REPEATABLE-READ,MySQL InnoDB 的標準配置。

2. 設置隔離級別

SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

將當前會話的隔離級別設為 SERIALIZABLE,確保後續事務串行執行,避免所有併發問題。

3. 讀未提交(READ UNCOMMITTED)

控制台 1

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT points FROM customers WHERE customer_id = 1;

控制台 2

START TRANSACTION;
UPDATE customers SET points = 20 WHERE customer_id = 1;
-- 未提交

在控制台 1 設置 READ UNCOMMITTED 後,查詢客戶 1 的積分(原為 2303)。控制台 2 更新積分為 20 但未提交,控制台 1 再次查詢將看到 20,體現了髒讀。若控制台 2 回滾,控制台 1 的查詢結果無效,可能誤導業務決策。

4. 讀已提交(READ COMMITTED)

控制台 1

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT points FROM customers WHERE customer_id = 1;

控制台 2

START TRANSACTION;
UPDATE customers SET points = 20 WHERE customer_id = 1;
COMMIT;

在控制台 1 設置 READ COMMITTED 後,查詢積分。若控制台 2 未提交更改,控制台 1 仍看到原值 2303,避免髒讀。控制台 2 提交後,控制台 1 查詢得到 20。但若在同一事務內多次查詢,可能因其他事務提交導致結果不一致,產生不可重複讀。

控制台 1(不可重複讀示例)

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
SELECT points FROM customers WHERE customer_id = 1;
-- 假設返回 20
SELECT points FROM customers WHERE customer_id = 1;
-- 返回 30
COMMIT;

控制台 2

START TRANSACTION;
UPDATE customers SET points = 30 WHERE customer_id = 1;
COMMIT;

控制台 1 第一次查詢得到 20,控制台 2 提交後更新為 30,控制台 1 第二次查詢得到 30,體現不可重複讀,數據一致性可能受影響。

5. 可重複讀(REPEATABLE READ)

控制台 1

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT points FROM customers WHERE customer_id = 1;
-- 返回 30
SELECT points FROM customers WHERE customer_id = 1;
-- 仍返回 30
COMMIT;

控制台 2

START TRANSACTION;
UPDATE customers SET points = 40 WHERE customer_id = 1;
COMMIT;

在 REPEATABLE READ 下,控制台 1 事務開始時創建一致性視圖,基於事務啟動時的快照(積分為 30)。控制台 2 提交更改為 40,但控制台 1 第二次查詢仍返回 30,避免不可重複讀。MVCC 確保事務內數據一致。

幻讀示例

控制台 1

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT * FROM customers WHERE state = 'CO';
-- 返回 1 條記錄
COMMIT;

控制台 2

START TRANSACTION;
UPDATE customers SET state = 'CO' WHERE customer_id = 1;
COMMIT;

控制台 1 查詢 state = 'CO' 的客戶,初始僅 1 條記錄。控制台 2 將客戶 1 的狀態改為 'CO' 並提交。控制台 1 提交事務後再次查詢,仍得到 1 條記錄,未反映數據庫最新狀態,產生幻讀。InnoDB 的間隙鎖可部分緩解幻讀。

6. 串行化(SERIALIZABLE)

控制台 1

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT * FROM customers WHERE state = 'CO';
COMMIT;

控制台 2

START TRANSACTION;
UPDATE customers SET state = 'CO' WHERE customer_id = 2;
COMMIT;

在 SERIALIZABLE 下,控制台 1 查詢 state = 'CO' 的客戶(初始 2 條)。控制台 2 嘗試將客戶 2 狀態改為 'CO' 但未提交,控制台 1 事務會被阻塞,等待控制台 2 提交,避免幻讀。提交後,控制台 1 查詢正確反映最新數據。

7. 死鎖

控制台 1

START TRANSACTION;
UPDATE customers SET state = 'VA' WHERE customer_id = 1;
UPDATE orders SET status = 1 WHERE order_id = 1;
COMMIT;

控制台 2

START TRANSACTION;
UPDATE orders SET status = 1 WHERE order_id = 1;
UPDATE customers SET state = 'VA' WHERE customer_id = 1;
COMMIT;

控制台 1 鎖定 customers 的行,嘗試鎖定 orders;控制台 2 鎖定 orders,嘗試鎖定 customers,形成循環依賴,導致死鎖。MySQL 檢測到死鎖後終止一個事務,報錯提示。規避死鎖需統一資源訪問順序或縮短事務長度。

總結

事務隔離級別決定了併發事務的數據可見性和一致性。READ UNCOMMITTED 性能高但風險大,SERIALIZABLE 安全但性能低,REPEATABLE READ 是 MySQL InnoDB 的默認折中方案。ATM 轉賬場景說明了隔離級別對數據一致性的重要性。本文基於 sql_store 數據庫,通過代碼示例解析四種隔離級別及死鎖問題。後續內容將探討索引設計或查詢優化,敬請關注。