首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 資料庫基礎

Oracle 併發控制與恢復機制深度解析:從語句層級到死鎖根因

     編輯:Oracle 資料庫基礎

核心觀念:語句層級的一致性視圖

一條合法的 SQL 執行時,對應資料庫的一個「資料狀態」。此狀態定義為:截至該執行時刻,沒有任何語句層級操作正在併發執行。換句話說,實際上正在併發的多條語句,可以假定在該語句之後執行。

強調「語句層級」是因為一個交易可能包含多條 SQL。若交易已執行前幾條、正執行第 N 條,不能簡單認為前幾條「還沒發生」——這取決於隔離等級。但在語句層級上,可以視為序列化執行。

語句執行過程中的狀態不變性

  • 執行期間,該語句看到的資料狀態凍結不變。
  • 執行結束時,才產生語句層級的資料狀態影響(如更新兩行、檢查唯一鍵)。
  • 若語句成功但交易稍後回滾,影響仍會被抹銷。
  • 語句成功提交後,才可能影響其他語句所見的資料狀態。

PL/SQL 如何被 Oracle 管理併發與恢復?

PL/SQL 在獨立的 PL/SQL 引擎中執行,引擎解析程式碼並不斷向 Oracle 發送 SQL。這與 Java 應用透過 JDBC 在同一 Session 中發送多條 SQL 本質無異。因此,Oracle 對併發與恢復的管理機制完全一致,無特殊差異。

死鎖產生機制與根因剖析

鎖機制基礎

Oracle 使用鎖控制併發。執行語句時,根據語句語意與隔離等級解析所需鎖類型與釋放時機。隔離等級越高,佔用鎖資源越多,死鎖機率越大。

經典死鎖場景

  1. 交易 A 取得鎖 L1、L2 未釋放。
  2. 交易 B 取得鎖 L3、L4 未釋放。
  3. A 請求 L3(被 B 持有)→ A 等待。
  4. B 請求 L1(被 A 持有)→ B 等待。
  5. 雙方循環等待,Oracle 偵測到死鎖,犧牲一方回滾。

根本原因

交易的 SQL 是分批發送給 Oracle,資料庫無法在交易開始時一次解析所有需要的鎖與釋放時機,無法統一排程。若無交易概念(單語句自動提交),Oracle 解析時已知所有鎖,若無法一次取得則等待,完全不會產生死鎖。

應對策略與權衡

方案一:應用層同步控制(作者實踐)

  • 降低 Oracle 隔離等級(如 Read Committed),僅倚賴原子性。
  • 在 Java 業務邏輯開始時,預先取得所有所需鎖(可用信號量、樹狀結構等靈活資料結構)。
  • 優點:消除死鎖、降低 DB 壓力、同步粒度靈活(不限表鎖/列鎖)。
  • 缺點:同步壓力移至應用端、研發門檻提高。

方案二:一次性提交交易所有 SQL(理論可行但現實困難)

若能在交易開始時將所有可能執行的 SQL 交給 Oracle,資料庫可預先鎖定資源。但業務邏輯中常夾雜非 DB 操作,且條件分支導致實際執行路徑不確定,會造成鎖資源浪費、降低併發度。

隔離等級的本質:權衡

允許幻讀(Read Committed)等較低隔離等級的存在,本質是在「應用自行控制併發的複雜度」與「資料庫併發吞吐量」之間的權衡。若應用不想自管併發、又想要高併發,必須在隔離等級上做取捨。

結語

理解 Oracle 併發控制的核心在於「語句層級序列化」與「交易分批送達的鎖無法預知」,死鎖是交易機制的必然代價。解決之道不外乎:提升應用層協調能力或接受資料庫層面的犧牲與重試。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved