數據庫領域為了解決ACID的平衡,嘗試了各種鎖、各種模式,
引擎技術特性、廠家實現方式各放異彩,被各種鎖折磨的小伙伴,是不是感同身受。
一、數據庫鎖
1. 鎖的類型與特點
- ?全局鎖?:鎖定整個數據庫實例,備份期間所有寫操作阻塞,業務停滯
- ?表級鎖?:鎖定整張表,批量操作時并發性差(如MySQL/PostgreSQL萬級TPS瓶頸)
- ?行級鎖?:細粒度鎖定單行,但高并發下仍存在三大致命缺陷?:
- ?阻塞等待?:事務A未提交時,事務B需排隊(如庫存扣減場景)
- ?死鎖風險?:循環等待資源(如轉賬場景中A等B、B等A)
- ?優先級反轉?:低優先級事務持有鎖時,高優先級事務被阻塞
2. ?鎖的本質矛盾?
- 悲觀鎖 →悲觀鎖假設并發沖突頻繁發生,因此在操作數據前立即加鎖,阻止其他線程訪問資源,直到當前操作完成
- 樂觀鎖 → 樂觀鎖假設并發沖突較少,操作數據時不加鎖,僅在提交時檢查數據是否被修改(沖突檢測),高并發但需重試邏輯
3. 鎖的分類
?共享鎖(S鎖)??
?原理?:允許多事務并發讀取同一資源,禁止寫入。
?場景?:高并發查詢(如報表系統),配合讀已提交隔離級別避免臟讀。
?排他鎖(X鎖)??
?原理?:事務修改數據時獨占資源,禁止其他事務讀寫。
?場景?:數據更新操作(如賬戶扣款),保障原子性。
?間隙鎖(Gap Lock)??
?原理?:鎖定索引記錄間的空白區間,防止新數據插入。
?場景?:可重復讀隔離級別下解決幻讀(如范圍查詢)。
?更新鎖(U鎖)??
?原理?:預鎖定待修改資源,避免共享鎖升級為排他鎖時的死鎖。
?場景?:先讀后寫的復合操作(如“查詢庫存后扣減”)。
?4. 事務的隔離級別對鎖的訴求又不一樣
隔離級別 | ?鎖機制? | ?解決痛點? | ?遺留問題? |
?讀未提交 | 寫操作加X鎖,讀操作無鎖 | 無 | 臟讀 |
?讀已提交? | 寫操作加X鎖,讀操作依賴MVCC | 臟讀 | 不可重復讀 |
?可重復讀? | 寫操作加X鎖,讀操作MVCC+間隙鎖 | 不可重復讀、部分幻讀 | 未完全解決幻讀 |
?串行化? | 讀寫均加鎖(表級或范圍鎖) | 所有并發問題 | 并發性能極差 |
5. ?技術特性對比?
?維度? | ?Lock-Free Reservations? | ?傳統行鎖? | ?樂觀鎖? |
?鎖持有時間? | 僅提交瞬間(毫秒級) | 整個事務周期 | 無鎖但需重試 |
?并發吞吐量? | 100萬+ TPS(無鎖競爭) | 1萬~10萬TPS(鎖競爭瓶頸) | 高但重試開銷大 |
?開發復雜度? | 聲明列屬性即可 | 需處理死鎖 | 需實現重試邏輯 |
二、Oracle 23 ai Lock-Free Reservations(無鎖列值保留)
1. ?原理創新:日志緩沖-原子合并?
-- 聲明可保留列
ALTER TABLE inv_test ADD (qty NUMBER RESERVABLE CHECK (qty >= 0));
-- 退回傳統鎖模式
ALTER TABLE inv_test MODIFY (qty NOT RESERVABLE);
- 無鎖操作?:對RESERVABLE列(如庫存qty)的加減操作(qty = qty ± N)?不鎖行,而是將增量值(如-50)寫入內部日志表SYS.RESV$JOURNAL
- ?原子提交?:事務提交時,日志值合并到原表,并自動校驗約束(如qty >= 0),違反則回滾
- 數據類型?:僅支持NUMBER/INTEGER/FLOAT(非數值列報錯ORA-55748)
- 語法限制?:必須使用±操作(直接賦值報錯ORA-55746)。
- 非保留列?:更新產品名稱等非RESERVABLE列時仍觸發行鎖。
三、實戰驗證:高并發庫存扣減測試?
1. ?驗證腳本?
SYS@CDB$ROOT> GRANT CREATE TABLESPACE TO QC;
Grant succeeded.
SYS@CDB$ROOT> GRANT CREATE SESSION TO QC;
Grant succeeded.
SYS@CDB$ROOT> GRANT ALTER TABLESPACE, DROP TABLESPACE TO QC;
Grant succeeded.
SYS@CDB$ROOT> commit;
Commit complete.
SYS@CDB$ROOT> ALTER USER QC QUOTA UNLIMITED ON users;
User QC altered.
SYS@CDB$ROOT> commit;
QC@localhost:1521/FREEPDB1> CREATE TABLESPACE inv_ts1 DATAFILE 'inv_ts1.dbf' SIZE 100M;
TABLESPACE INV_TS1 created.
SYS@CDB$ROOT> create user QC identified by Oracle_4U;
User QC created.
SYS@CDB$ROOT> GRANT CREATE TABLE, ALTER ANY TABLE TO QC;
Grant succeeded.
[oracle@OL96 ~]$ sql QC/Oracle_4U@localhost:1521/FREEPDB1;
-- --1:啟用無鎖列(Oracle 23ai)
CREATE TABLE inv_test (item_id NUMBER PRIMARY KEY,qty NUMBER RESERVABLE CHECK (qty >= 0) -- 關鍵聲明
);
INSERT INTO inv_test VALUES (1, 100);
COMMIT;-- --2:并發扣減(兩個會話)
-- 會話1:扣減50(不提交)
UPDATE inv_test SET qty = qty - 50 WHERE item_id=1;-- 會話2:扣減30(立即執行,無阻塞!)
UPDATE inv_test SET qty = qty - 30 WHERE item_id=1;
COMMIT;
-- 會話2先提交-- 會話1提交
COMMIT; -- 合并日志:100-50-30=20,校驗通過-- --3:結果驗證
SELECT * FROM inv_test;
QC@localhost:1521/FREEPDB1> SELECT * FROM inv_test;ITEM_ID QTY
__________ ______1 20-- --4:觸發約束保護(故意超扣)
UPDATE inv_test SET qty = qty - 150 WHERE item_id=1;
-- 提交時報錯ORA-02290(違反CHECK約束)
QC@localhost:1521/FREEPDB1> UPDATE inv_test SET qty = qty - 150 WHERE item_id=1;Error starting at line : 1 in command -
UPDATE inv_test SET qty = qty - 150 WHERE item_id=1
Error report -
ORA-02290: check constraint (QC.SYS_C008612) violated
Help: https://docs.oracle.com/error-help/db/ora-02290/
2. ?工作流程解析?
3. ?驗證要點?
- 無阻塞?:會話2無需等待會話1提交即可執行更新
- 約束保護?:扣減后qty<0時自動回滾。
- 日志追溯?(DBA權限):
-- 查看-50、-30日志,Oracle 23 ai free中無此視圖,DBA_EXTENDED_TXN_DETAILS,也不存在
SELECT * FROM SYS.RESV$JOURNAL WHERE table_name='inv_test';
四、適用場景和特性
1. ?最佳場景
?場景類型? | ?案例? | ?性能提升? |
?OLTP高頻更新? | 庫存扣減(秒殺) | 并發提升10倍+ |
?金融交易? | 賬戶余額實時更新 | 延遲降至毫秒級 |
?計數系統? | 點贊/投票計數 | 無鎖寫入 |
?
2. 并發控制的新范式?
- ?OLTP系統?:徹底消除熱點數據鎖競爭,吞吐量提升10倍+。
- ?開發者體驗?:無需重寫應用代碼,聲明列屬性即獲性能飛躍。
- ?未來生態?:與AI Vector Search協同處理結構化+非結構化混合負載
?