H2 數據庫中的鎖機制深度解析與實戰關鍵字
H2 數據庫的鎖機制是併發控制的核心,通過一系列關鍵字實現對行、表級別的鎖控制,平衡數據一致性與併發性能。以下從鎖類型精準控制、鎖行為優化、鎖狀態查詢三個維度,結合實戰場景詳解核心關鍵字,覆蓋高併發場景下的鎖使用技巧。
一、鎖類型核心關鍵字(精準控制鎖粒度)
1. 行級鎖關鍵字:FOR UPDATE(排他行鎖)
-
作用:查詢時對匹配行加排他鎖,阻止其他事務修改 / 刪除該數據,直到當前事務提交 / 回滾。
-
實戰場景:秒殺下單、餘額扣減等 “查詢 - 修改” 原子操作,避免超賣或重複扣減。
-- 秒殺場景:鎖定商品庫存,防止超賣
BEGIN;
-- 鎖定商品ID=1001的記錄,其他事務無法修改庫存
SELECT stock FROM products WHERE product_id = 1001 FOR UPDATE;
-- 扣減庫存(僅當前事務可執行)
UPDATE products SET stock = stock - 1 WHERE product_id = 1001;
-- 生成訂單
INSERT INTO orders (product_id, user_id, order_time) VALUES (1001, 5001, CURRENT_TIMESTAMP);
COMMIT;
- 進階用法:FOR UPDATE SKIP LOCKED(跳過已鎖定行),適用於併發搶單場景,避免事務阻塞:
-- 跳過已被其他事務鎖定的商品,直接查詢可用庫存
SELECT product_id, stock FROM products WHERE category_id = 3 AND stock > 0 FOR UPDATE SKIP LOCKED LIMIT 1;
2. 共享行鎖關鍵字:SHARE MODE
-
作用:對匹配行加共享鎖,允許其他事務加共享鎖(查詢),但禁止加排他鎖(修改 / 刪除)。
-
實戰場景:多事務併發查詢同一數據(如統計報表),避免查詢期間數據被修改導致結果不一致。
-- 統計期間鎖定數據,允許其他查詢但禁止修改
BEGIN;
SELECT SUM(pay_amount) FROM orders WHERE order_date = '2024-10-01' SHARE MODE;
-- 執行統計計算,其他事務可查詢該訂單數據但無法修改
COMMIT;
3. 表級鎖關鍵字:LOCK TABLE ... IN [MODE]
-
鎖模式:EXCLUSIVE(排他表鎖)、SHARE(共享表鎖)
-
作用:對整個表加鎖,粒度比行級鎖粗,適用於批量操作或表結構修改。
-
實戰場景 1:批量更新(排他表鎖)
-- 批量更新前加排他表鎖,禁止其他事務讀寫
LOCK TABLE orders IN EXCLUSIVE MODE;
-- 批量更新過期訂單狀態(無併發干擾)
UPDATE orders SET status = '已過期' WHERE order_time < '2024-01-01';
COMMIT; -- 提交後釋放鎖
- 實戰場景 2:全局統計(共享表鎖)
-- 加共享表鎖,允許其他事務查詢但禁止修改
LOCK TABLE products IN SHARE MODE;
-- 統計全表商品庫存總量
SELECT category_id, SUM(stock) FROM products GROUP BY category_id;
COMMIT;
二、鎖行為優化關鍵字(避免阻塞與死鎖)
1. 鎖超時控制:SET LOCK_TIMEOUT
-
作用:設置獲取鎖的超時時間(毫秒),超時未獲取鎖則拋出異常,避免事務無限期阻塞。
-
實戰場景:高併發場景下防止單個事務阻塞導致系統雪崩。
-- 設置鎖超時時間為3秒(3000毫秒)
SET LOCK_TIMEOUT 3000;
BEGIN;
-- 若3秒內未獲取商品行鎖,直接拋出異常
SELECT stock FROM products WHERE product_id = 1001 FOR UPDATE;
UPDATE products SET stock = stock - 1 WHERE product_id = 1001;
COMMIT;
2. 非阻塞鎖:FOR UPDATE NOWAIT
-
作用:獲取鎖時若發現已被佔用,直接拋出異常而非阻塞,適用於 “快速失敗” 場景。
-
實戰場景:用户搶券、秒殺等場景,避免用户長時間等待。
-- 嘗試鎖定優惠券,失敗直接返回,不阻塞
BEGIN;
SELECT coupon_id FROM user_coupons WHERE user_id = 5001 AND status = '未使用' FOR UPDATE NOWAIT;
-- 領取優惠券(失敗則事務回滾)
UPDATE user_coupons SET status = '已使用' WHERE coupon_id = 8001;
COMMIT;
3. 死鎖檢測:SET DEADLOCK_TIMEOUT
- 作用:設置死鎖檢測超時時間,H2 會自動檢測死鎖並終止其中一個事務,避免死鎖導致的系統卡死。
-- 設置死鎖檢測超時為2秒
SET DEADLOCK_TIMEOUT 2000;
-- 事務1
BEGIN;
SELECT * FROM users WHERE user_id = 1 FOR UPDATE;
SELECT * FROM orders WHERE order_id = 100 FOR UPDATE;
-- 事務2(併發執行)
BEGIN;
SELECT * FROM orders WHERE order_id = 100 FOR UPDATE;
SELECT * FROM users WHERE user_id = 1 FOR UPDATE;
-- 死鎖檢測觸發後,其中一個事務會被終止,拋出死鎖異常
三、鎖狀態查詢關鍵字(運維監控)
1. 查看當前鎖持有情況:INFORMATION_SCHEMA.LOCKS
- 作用:通過系統表查詢當前數據庫的鎖狀態,包括鎖類型、持有事務、鎖定對象等。
-- 查詢所有持有鎖的信息
SELECT
LOCK_TYPE, -- 鎖類型(TABLE/ROW)
LOCK_MODE, -- 鎖模式(EXCLUSIVE/SHARE)
TABLE_NAME, -- 鎖定表名
TRANSACTION_ID, -- 持有鎖的事務ID
LOCKED_BY -- 持有鎖的會話
FROM INFORMATION_SCHEMA.LOCKS;
2. 查看事務狀態:INFORMATION_SCHEMA.TRANSACTIONS
- 作用:查詢當前活躍事務,輔助定位長時間持有鎖的事務。
-- 查詢所有活躍事務及鎖信息
SELECT
TRANSACTION_ID,
START_TIME, -- 事務啓動時間
STATE, -- 事務狀態(ACTIVE/COMMITTED/ROLLED_BACK)
LOCK_COUNT -- 事務持有鎖數量
FROM INFORMATION_SCHEMA.TRANSACTIONS WHERE STATE = 'ACTIVE';
四、鎖機制關鍵字使用原則
-
最小鎖粒度:優先使用行級鎖(FOR UPDATE/SHARE MODE),避免濫用表級鎖導致併發性能下降。
-
最短鎖持有時間:事務中僅在需要時加鎖,執行完核心操作後立即提交 / 回滾,減少鎖佔用時間。
-
避免循環鎖:多個事務操作同一組表時,按固定順序加鎖(如先鎖用户表再鎖訂單表),防止死鎖。
-
合理設置超時:通過LOCK_TIMEOUT/DEADLOCK_TIMEOUT避免事務阻塞或死鎖導致的系統不穩定。
這些鎖機制關鍵字覆蓋了從鎖類型選擇、行為優化到運維監控的全流程,在高併發場景(如秒殺、轉賬、庫存管理)中,合理運用FOR UPDATE、LOCK TABLE、SET LOCK_TIMEOUT等關鍵字,能有效保障數據一致性,同時最大化併發性能,讓 H2 數據庫在複雜併發環境中穩定運行。