SQL進階之旅 Day 20:鎖與并發控制技巧

【JDK21深度解密 Day 20】鎖與并發控制技巧

文章簡述

在高并發的數據庫環境中,鎖與并發控制是保障數據一致性和系統穩定性的核心機制。本文作為“SQL進階之旅”系列的第20天,深入探討SQL中的鎖機制、事務隔離級別以及并發控制策略。文章從理論基礎入手,結合MySQL和PostgreSQL的實現差異,詳細講解了行級鎖、表級鎖、死鎖預防等關鍵技術點,并通過實際業務場景分析,提供可執行的SQL代碼示例及性能對比測試。無論你是數據庫開發工程師還是后端開發者,掌握這些內容都將顯著提升你在高并發系統中處理數據沖突的能力。


理論基礎

1. 什么是鎖?

鎖(Lock)是數據庫管理系統用于管理多個事務對共享資源(如數據行、表等)訪問的一種機制。其主要目的是確保在多用戶并發操作時,數據的一致性與完整性。

2. 鎖的類型

行級鎖(Row-Level Locking)
  • 特點:鎖定單個數據行,適用于高并發寫入場景。
  • 優點:減少鎖沖突,提高并發性能。
  • 缺點:管理開銷較大。
  • 適用數據庫:MySQL InnoDB、PostgreSQL(默認使用行級鎖)。
表級鎖(Table-Level Locking)
  • 特點:鎖定整張表,通常用于只讀或批量操作。
  • 優點:實現簡單,開銷小。
  • 缺點:限制并發性,可能導致性能瓶頸。
  • 適用數據庫:MySQL MyISAM、某些舊版本的Oracle。
頁級鎖(Page-Level Locking)
  • 特點:鎖定一個數據頁,介于行級和表級之間。
  • 常見于:部分數據庫引擎(如SQL Server)。

3. 事務隔離級別

事務隔離級別決定了事務在并發執行時如何相互影響。常見的四種隔離級別如下:

隔離級別臟讀不可重復讀幻讀
Read Uncommitted???
Read Committed???
Repeatable Read???
Serializable???
  • Read Committed 是大多數數據庫的默認隔離級別。
  • Repeatable Read 在MySQL中默認為InnoDB的隔離級別,但可能產生幻讀問題。
  • Serializable 是最嚴格的隔離級別,犧牲性能換取一致性。

4. 死鎖(Deadlock)

當兩個或多個事務互相等待對方釋放資源時,就會發生死鎖。數據庫系統通常會檢測并自動回滾其中一個事務以解除死鎖。


適用場景

以下是一些典型的需要鎖與并發控制的業務場景:

場景一:庫存扣減系統

在電商系統中,用戶下單時需同時更新商品庫存和訂單狀態。如果多個用戶同時請求同一商品,必須保證庫存不會被超賣。

場景二:銀行轉賬系統

當A向B轉賬時,必須確保賬戶余額的原子性和一致性,防止因并發操作導致的數據錯誤。

場景三:日志記錄系統

在高并發下,多個線程同時寫入日志表,若不加鎖,可能會出現日志丟失或重復插入的問題。


代碼實踐

示例一:使用 SELECT ... FOR UPDATE 實現行級鎖

-- 創建測試表
CREATE TABLE inventory (product_id INT PRIMARY KEY,stock INT NOT NULL
);-- 插入測試數據
INSERT INTO inventory (product_id, stock) VALUES (1, 100);-- 開啟事務
START TRANSACTION;-- 查詢并鎖定該行
SELECT * FROM inventory WHERE product_id = 1 FOR UPDATE;-- 修改庫存(模擬扣減)
UPDATE inventory SET stock = stock - 1 WHERE product_id = 1;-- 提交事務
COMMIT;

注釋:

  • FOR UPDATE 是MySQL InnoDB中用于獲取行級鎖的關鍵字。
  • 在PostgreSQL中,可以使用 SELECT ... FOR UPDATESELECT ... SKIP LOCKED 來實現類似功能。

示例二:使用 BEGIN; ... COMMIT; 控制事務邊界

-- 開始事務
BEGIN;-- 扣減庫存
UPDATE inventory SET stock = stock - 1 WHERE product_id = 1;-- 記錄日志
INSERT INTO logs (action, description) VALUES ('stock_decrease', 'Product 1 decreased by 1');-- 提交事務
COMMIT;

注釋:

  • 使用顯式事務控制,確保操作的原子性。
  • 如果中間發生異常,可以通過 ROLLBACK; 回滾事務。

示例三:避免死鎖的實踐方法

-- 事務A
START TRANSACTION;
UPDATE orders SET status = 'paid' WHERE order_id = 1001;
UPDATE inventory SET stock = stock - 1 WHERE product_id = 1;
COMMIT;-- 事務B
START TRANSACTION;
UPDATE inventory SET stock = stock - 1 WHERE product_id = 1;
UPDATE orders SET status = 'paid' WHERE order_id = 1001;
COMMIT;

注釋:

  • 上述兩個事務如果同時執行,可能造成死鎖。
  • 建議統一按相同順序更新資源,避免循環依賴。

執行原理

MySQL InnoDB 的鎖機制

  • InnoDB 使用 意向鎖(Intention Locks) 來表示事務對表的意圖(如讀或寫)。
  • 行級鎖由 鎖管理器(Lock Manager) 維護,每個鎖對象包含鎖類型、事務ID、等待隊列等信息。
  • 當事務嘗試獲取鎖失敗時,會進入等待隊列,直到鎖被釋放或超時。

PostgreSQL 的鎖機制

  • PostgreSQL 支持 行級鎖(Row Share/Exclusive)表級鎖(Share/Access Exclusive)
  • 默認使用 MVCC(Multi-Version Concurrency Control) 技術來實現無鎖并發控制。
  • SELECT ... FOR UPDATE 會阻塞其他事務對該行的修改,直到當前事務提交或回滾。

性能測試

我們使用MySQL 8.0和PostgreSQL 14進行性能對比測試,測試環境為本地虛擬機,數據量約為10萬條記錄。

測試表結構

CREATE TABLE test_table (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(100),value INT
);-- 插入10萬條測試數據
INSERT INTO test_table (name, value)
SELECT CONCAT('Test', LPAD(seq, 5, '0')), FLOOR(RAND() * 1000)
FROM (WITH RECURSIVE seq AS (SELECT 1 AS nUNION ALLSELECT n + 1 FROM seq WHERE n < 100000)SELECT * FROM seq
) AS seq;

測試用例一:未加鎖的并發更新

-- 事務A
START TRANSACTION;
UPDATE test_table SET value = value + 1 WHERE id BETWEEN 1 AND 1000;
COMMIT;-- 事務B
START TRANSACTION;
UPDATE test_table SET value = value + 1 WHERE id BETWEEN 1 AND 1000;
COMMIT;
測試項MySQL 8.0PostgreSQL 14
平均耗時(ms)600550
數據一致性??

測試用例二:加鎖后的并發更新

-- 事務A
START TRANSACTION;
SELECT * FROM test_table WHERE id BETWEEN 1 AND 1000 FOR UPDATE;
UPDATE test_table SET value = value + 1 WHERE id BETWEEN 1 AND 1000;
COMMIT;-- 事務B
START TRANSACTION;
SELECT * FROM test_table WHERE id BETWEEN 1 AND 1000 FOR UPDATE;
UPDATE test_table SET value = value + 1 WHERE id BETWEEN 1 AND 1000;
COMMIT;
測試項MySQL 8.0PostgreSQL 14
平均耗時(ms)12001100
數據一致性??

注釋:

  • 加鎖后雖然耗時增加,但數據一致性得到保障。
  • PostgreSQL的MVCC機制在高并發下表現更優。

最佳實踐

1. 合理選擇鎖類型

  • 對于高并發寫入場景,優先使用 行級鎖
  • 對于批量讀取或只讀操作,使用 表級鎖 可減少鎖競爭。

2. 控制事務范圍

  • 盡量保持事務 短小精悍,避免長時間持有鎖。
  • 避免在事務中執行復雜查詢或外部調用,以免增加鎖等待時間。

3. 避免死鎖

  • 按固定順序訪問資源,避免循環依賴。
  • 使用 SET lock_timeout = '5s'; 設置鎖等待超時時間,防止事務無限等待。

4. 使用 MVCC 優化并發

  • PostgreSQL 的 MVCC 機制減少了鎖的使用,適合高并發寫入場景。
  • MySQL 的 InnoDB 也支持類似機制,但在某些情況下仍需顯式加鎖。

5. 監控鎖等待和死鎖

  • 使用 SHOW ENGINE INNODB STATUS\G 查看鎖等待和死鎖信息。
  • 在PostgreSQL中,可通過 pg_locks 系統視圖監控鎖狀態。

案例分析

案例背景

某電商平臺在促銷期間出現了大量庫存超賣的情況。系統在高并發下頻繁出現“庫存不足”卻仍然扣減庫存的現象。

問題分析

  • 由于沒有使用行級鎖,多個事務同時讀取庫存值并進行更新,導致最終結果不一致。
  • 缺乏事務控制,無法保證操作的原子性。

解決方案

  1. 使用 SELECT ... FOR UPDATE 鎖定庫存行
  2. 使用事務包裹整個操作流程
  3. 增加庫存檢查邏輯

優化后的SQL

-- 開始事務
START TRANSACTION;-- 獲取并鎖定庫存
SELECT stock FROM inventory WHERE product_id = 1 FOR UPDATE;-- 檢查庫存是否足夠
IF @stock >= 1 THENUPDATE inventory SET stock = stock - 1 WHERE product_id = 1;INSERT INTO orders (product_id, quantity) VALUES (1, 1);
END IF;-- 提交事務
COMMIT;

注釋:

  • 通過鎖定行并檢查庫存,確保扣減操作的正確性。
  • 使用事務保證操作的原子性。

總結

本篇文章圍繞“鎖與并發控制”這一關鍵主題展開,從理論到實踐全面解析了SQL中的鎖機制、事務隔離級別以及并發控制策略。通過具體代碼示例和性能測試,展示了不同鎖類型對系統性能和數據一致性的影響。結合實際案例,進一步說明了如何在高并發場景下有效避免數據沖突和死鎖問題。

在接下來的Day 21中,我們將深入探討“臨時表與內存表應用”,了解如何利用內存表優化查詢性能,提升系統響應速度。敬請期待!


核心技能總結

技能點應用場景實際價值
行級鎖與表級鎖高并發寫入、批量操作減少鎖沖突,提升并發性能
事務控制數據一致性要求高的場景保證操作的原子性和一致性
死鎖預防多事務交互場景避免系統阻塞,提高穩定性
MVCC機制高并發讀寫場景降低鎖開銷,提升吞吐量
鎖等待監控生產環境故障排查快速定位并發瓶頸,優化系統性能

文章標簽

sql, database, concurrency, locking, transaction, mysql, postgresql, performance, optimization, advanced-sql


進一步學習參考資料

  1. MySQL官方文檔 - InnoDB Locking
  2. PostgreSQL官方文檔 - Locking
  3. 《高性能MySQL》第三版 - 第10章 鎖定
  4. Database Systems Concepts - Concurrency Control
  5. CSDN技術專欄 - SQL鎖與并發控制實戰

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

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

相關文章

Qt(part 2)1、Qwindow(菜單欄,工具欄,狀態欄),鉚接部件,核心部件 ,2、添加資源文件 3、對話框

1、Qwindow tips&#xff1a;1&#xff0c;首先為什么創建出的對象基本都是指針形式&#xff0c;個人覺得是對象樹的原因&#xff08;自動釋放內存&#xff09;&#xff0c;指針來訪問成員函數->的形式。2&#xff0c;菜單欄只能一個的&#xff0c;放窗口基本Set&#xff0c…

一款“短小精悍的”手機錄屏軟件

這個時代&#xff0c;手機自帶錄屏功能已經不是什么稀奇的事情了&#xff0c;但是手機自帶的錄屏功能不都是完美的&#xff0c;無法靜音錄屏、、不能修改畫質、不能剪輯、不能自定義水印......emmm.....貌似除了錄屏就什么都不會 今天分享的這款軟件——ADV屏幕錄制漢化版&…

力扣HOT100之二分查找:153. 尋找旋轉排序數組中的最小值

這道題是上一道題&#xff1a;33. 搜索旋轉排序數組的前置題&#xff0c;有點沒看懂力扣為什么要這樣安排題目順序&#xff0c;應該把這道題按排在前面才對啊。。。這道題的思路已經在上一道題的思路中說過了&#xff0c;這里就直接復制粘貼上一篇博客中的內容了。 我們閱讀完題…

libiec61850 mms協議異步模式

之前項目中使用到libiec61850庫&#xff0c;都是服務端開發。這次新的需求要接收服務端的遙測數據&#xff0c;這就涉及到客戶端開發了。 客戶端開發沒搞過啊&#xff0c;挑戰不少&#xff0c;但是人不就是通過戰勝困難才成長的嘛。通過查看libiec61850的客戶端API發現&#xf…

【 知你所想 】基于ernie-x1-turbo推理模型實現趣味猜心游戲

&#x1f31f; 項目特點 &#x1f916; 智能AI&#xff1a;基于文心一言大模型&#xff0c;具有強大的推理能力&#x1f3af; 實時思考&#xff1a;展示AI的思考過程&#xff0c;讓你了解AI是如何推理的&#x1f3ae; 互動性強&#xff1a;通過簡單的"是/否"問答&…

Excel 模擬分析之單變量求解簡單應用

正向求解 利用公式根據貸款總額、還款期限、貸款利率&#xff0c;求每月還款金額 反向求解 根據每月還款能力&#xff0c;求最大能承受貸款金額 參數&#xff1a; 目標單元格&#xff1a;求的值所在的單元格 目標值&#xff1a;想要達到的預期值 可變單元格&#xff1a;變…

關于easyexcel動態下拉選問題處理

前些日子突然碰到一個問題&#xff0c;說是客戶的導入文件模版想支持部分導入內容的下拉選&#xff0c;于是我就找了easyexcel官網尋找解決方案&#xff0c;并沒有找到合適的方案&#xff0c;沒辦法只能自己動手并分享出來&#xff0c;針對Java生成Excel下拉菜單時因選項過多導…

【Qt】之【Get√】【Bug】通過值捕獲(或 const 引用捕獲)傳進 lambda,會默認復制成 const

通過值捕獲&#xff08;或 const 引用捕獲&#xff09;傳進 lambda&#xff0c;會默認復制成 const。 背景 匿名函數外部定義 QSet<QString> nameSet,需要傳入匿名函數使用修改 connect(dlg, ..., [nameSet](...) {nameSet.insert(name); // ? 這里其實是 const QSet…

css元素的after制作斜向的刪除線

<div class"price_div"></div>.price_div{position: relative; } ::after{content: ;position: absolute;left: 0;top: 50%;width: 100%;height: 2px;background: #FF186B;transform: rotate(-5deg); }

uniapp map組件的基礎與實踐

UniApp 中的 map 組件用于在應用中展示地圖,并且支持在地圖上添加標記、繪制線條和多邊形等功能。以下是一些基本用法: 1. 基本結構 首先,確保你在頁面的 .vue 文件中引入了 map 組件。以下是創建一個簡單地圖的基本代碼結構: <template><view class="con…

深入理解PHP安全漏洞:文件包含與SSRF攻擊全解析

深入理解PHP安全漏洞&#xff1a;文件包含與SSRF攻擊全解析 前言 在Web安全領域&#xff0c;PHP應用程序的安全問題一直備受關注。本文將深入探討兩種常見的PHP安全漏洞&#xff1a;文件包含漏洞和服務器端請求偽造(SSRF)&#xff0c;幫助開發者理解漏洞原理、利用方式以及防…

MS358A 低功耗運算放大器 車規

MS358A 低功耗運算放大器 車規 產品簡述 MS358A 是雙通道運算放大器&#xff0c;具有低功耗、寬電源電壓范圍、高單位增益帶寬的特性。在特定情況下&#xff0c;壓擺率可以達到0.4V/μs 。每個通道的靜態電流 (5V) 只有 430μA 。 MS358A輸入共模范圍可以到地&#xff0c;同時…

n8n + AI Agent:AI 自動化生成測試用例并支持導出 Excel

n8n + AI Agent:AI 自動化生成測試用例并支持導出 Excel 最終成果展示一、準備工作二、手把手搭建工作流第一步:創建手動觸發器 (Chat Trigger)第二步:創建 AI Agent 節點第三步:為 AI Agent 植入 DeepSeek AI 模型第四步:解析AI的響應 (Code)第五步:生成Excel文件 (Conv…

5.1 HarmonyOS NEXT系統級性能調優:內核調度、I/O優化與多線程管理實戰

HarmonyOS NEXT系統級性能調優&#xff1a;內核調度、I/O優化與多線程管理實戰 在HarmonyOS NEXT的全場景生態中&#xff0c;系統級性能調優是構建流暢、高效應用的關鍵。通過內核調度精細化控制、存儲與網絡I/O深度優化&#xff0c;以及多線程資源智能管理&#xff0c;開發者…

?線性注意力 vs. 傳統注意力:效率與表達的博弈新解

?核心結論?&#xff1a;線性注意力用計算復雜度降維換取全局建模能力&#xff0c;通過核函數和結構優化補足表達缺陷 一、本質差異&#xff1a;兩種注意力如何工作&#xff1f; ?特性?傳統注意力&#xff08;Softmax Attention&#xff09;線性注意力&#xff08;Linear At…

github中main與master,master無法合并到main

文章目錄 遇到問題背景怎么做 遇到問題 上傳 github 時候&#xff0c;發現傳上去的是 master&#xff0c;但是 github 竟然還有一個 main 背景 github 采用 main 替代 master 作為主分支不是出于技術背景&#xff0c;而是出于 2020 年全球范圍內興起的 “Black Lives Matter…

使用矩陣乘法+線段樹解決區間歷史和問題的一種通用解法

文章目錄 前言P8868 [NOIP2022] 比賽CF1824DP9990/2020 ICPC EcFinal G 前言 一般解決普通的區間歷史和&#xff0c;只需要定義輔助 c h s ? t ? a chs-t\cdot a chs?t?a&#xff0c; h s hs hs是歷史和&#xff0c; a a a是區間和&#xff0c; t t t是時間戳&#xff0c…

RabbitMQ入門4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年開發&#xff0c;后來由Pivotal Software Inc.&#xff08;現為VMware子公司&#xff09;接管。RabbitMQ 是一個開源的消息代理和隊列服務器&#xff0c;用 Erlang 語言編寫。廣泛應用于各種分布…

Python Copilot【代碼輔助工具】 簡介

粉絲愛買鱈魚腸深海鱈魚肉魚肉香腸盼盼麥香雞味塊卡樂比&#xff08;Calbee&#xff09;薯條三兄弟 獨立小包美麗雅 奶茶杯一次性飲料杯好時kisses多口味巧克力糖老金磨方【黑金系列】黑芝麻丸鄭新初網紅鄭新初烤鮮牛肉干超人毛球修剪器去球器剃毛器衣服去毛器優惠券寧之春 紅黑…

VBA進度條ProgressForm1

上一章《VBA如何使用ProgressBar進度條控件》介紹了ProgressBar控件的使用方法&#xff0c;今天我給大家介紹ProgressForm1進度條的使用方法&#xff0c;ProgressForm1是集成ProgressBar控件和Label控件的窗體&#xff0c;可以同時顯示進度條和百分比&#xff0c;如下圖&#x…