4. Oracle 锁机制详解:TX 锁、TM 锁、DDL 锁、DML 锁、Enqueue 锁,以及 v$lock 视图解读

Oracle 数据库的锁机制是保障并发事务一致性与隔离性的核心。在变更台账锁等待排查中,理解锁的类型、级别及视图是定位阻塞链的基石。本章将系统梳理 Oracle 锁的分类体系,并深入解读 v$lock 视图。

4.1 锁的分类与层级

Oracle 锁按保护对象与作用范围可分为以下层级:

分类维度 锁类型 保护对象 典型场景
按模式 DML 锁(Data Manipulation Lock) 表数据行 INSERT / UPDATE / DELETE / SELECT … FOR UPDATE
DDL 锁(Data Definition Lock) 对象定义(表、索引、视图等) ALTER TABLE / DROP TABLE / TRUNCATE
按结构 TX 锁(Transaction Lock) 事务本身(行级锁的载体) 任何 DML 事务
TM 锁(Table Manipulation Lock) 表级锁 DML 操作时防止 DDL 冲突
按排队机制 Enqueue 锁 共享资源(队列化访问) TX / TM / ST / HW 等锁的底层实现
排查要点: 锁等待排查中,TX 锁 是最常见的阻塞源,通常表现为一个事务持有行锁,另一个事务等待同一行;TM 锁 则常出现在 DDL 与 DML 并发冲突时。

4.2 TX 锁(事务锁)

TX 锁是 Oracle 实现行级锁的核心机制。每个执行 DML 的事务在修改第一行数据时,会自动申请一个 TX 锁(Enqueue 类型为 TX)。TX 锁并不直接锁住行,而是通过数据块上的 ITL(Interested Transaction List,感兴趣事务列表) 记录事务 ID,行上的 Lock Byte 指向 ITL 条目。

  • 持有模式: 排他(X)——事务提交或回滚后释放。
  • 等待模式: 共享(S)——其他事务等待同一行时,会在 TX 锁上排队。
  • 典型等待事件: enq: TX - row lock contention(行锁争用)、enq: TX - allocate ITL entry(ITL 槽不足)。
实战口诀: TX 锁是“事务身份证”,行锁是“座位号”。一个事务可以锁多行,但只持有一个 TX 锁。

4.3 TM 锁(表锁)

TM 锁用于保护表结构不被 DDL 操作意外修改。当一个事务对表执行 DML 时,Oracle 会自动在该表上获取一个 TM 锁(Enqueue 类型为 TM)。TM 锁的 锁模式(LMODE) 决定了 DDL 操作能否通过:

LMODE 值 模式名称 含义 典型操作
2 RS(Row Share) 行级共享锁,允许其他 DML,禁止 DDL 修改表结构 SELECT … FOR UPDATE
3 RX(Row Exclusive) 行级排他锁,允许其他 DML,禁止 DDL INSERT / UPDATE / DELETE
4 S(Share) 共享锁,允许其他查询,禁止 DML 和 DDL LOCK TABLE … IN SHARE MODE
5 SRX(Share Row Exclusive) 共享行排他锁,禁止其他 DML 和 DDL LOCK TABLE … IN SHARE ROW EXCLUSIVE MODE
6 X(Exclusive) 排他锁,禁止所有并发操作 LOCK TABLE … IN EXCLUSIVE MODE / DDL
常见陷阱: 未提交事务长时间持有 TM 锁(RX 模式),会导致 ALTER TABLE 或 TRUNCATE 操作被阻塞,等待事件为 enq: TM - contention。

4.4 DML 锁与 DDL 锁

4.4.1 DML 锁

DML 锁是用户执行数据操作时自动获取的锁组合:

  • 行锁(Row Lock): 通过 TX 锁 + ITL 实现,锁住被修改的行。
  • 表锁(Table Lock): 通过 TM 锁实现,防止表结构被并发 DDL 修改。

DML 锁的释放时机:事务提交(COMMIT)或回滚(ROLLBACK)后立即释放。

4.4.2 DDL 锁

DDL 锁在对象定义变更时自动获取,用于保护数据字典的完整性:

  • 排他 DDL 锁(Exclusive DDL Lock): 如 ALTER TABLE … MOVE、DROP TABLE,阻止所有并发 DML 和 DDL。
  • 共享 DDL 锁(Share DDL Lock): 如 CREATE INDEX(在线模式),允许 DML 但阻止其他 DDL。
  • 可中断解析锁(Breakable Parse Lock): 用于缓存游标,DDL 会使相关游标失效。
排查技巧: DDL 锁等待通常表现为 enq: TM - contention 或 library cache lock。检查 v$session 中 blocking_session 字段,定位持有锁的会话。

4.5 Enqueue 锁(队列锁)

Enqueue 是 Oracle 实现锁排队与序列化的底层机制。每个 Enqueue 锁由 类型(TYPE) 和 ID1/ID2 唯一标识。常见的 Enqueue 类型包括:

类型 全称 说明
TX Transaction 事务锁,行级锁的排队载体
TM Table Manipulation 表锁,保护表结构
ST Space Transaction 空间事务锁,用于表空间/段空间管理
HW High Watermark 高水位锁,用于段空间扩展
UL User Lock 用户自定义锁(DBMS_LOCK)

Enqueue 锁的排队机制通过 锁队列(Lock Queue) 实现,等待会话会挂在持有会话的链表上,形成等待链。

Oracle 锁体系结构总览 Oracle 锁体系结构总览 DML 锁 DDL 锁 Enqueue 锁 TX 锁(事务锁) TM 锁(表锁) TX / TM / ST / HW … ITL + Lock Byte LMODE 模式矩阵 锁队列 + 排队机制 核心关系 DML 锁 = TX 锁(行级)+ TM 锁(表级) | DDL 锁 = 排他/共享 DDL 锁 | Enqueue 是底层排队实现

4.6 v$lock 视图深度解读

v$lock 是排查锁等待的核心动态性能视图,记录了当前数据库中所有 Enqueue 锁的持有与等待信息。以下为关键字段说明:

字段名 类型 说明 排查用途
SID NUMBER 会话 ID 关联 v$session 定位会话
TYPE VARCHAR2(2) Enqueue 类型(TX / TM / ST 等) 区分锁类型
ID1 NUMBER 锁资源标识符(对于 TX 锁,包含回滚段号+槽号) 判断是否等待同一行
ID2 NUMBER 锁资源标识符(对于 TX 锁,通常为包装号) 与 ID1 共同唯一标识锁资源
LMODE NUMBER 当前会话持有的锁模式(0=无锁,2=RS,3=RX,6=X 等) 判断锁的强度
REQUEST NUMBER 当前会话请求的锁模式(0=无请求,>0 表示等待) 识别等待会话
CTIME NUMBER 锁持有或等待的持续时间(秒) 判断锁等待时长
BLOCK NUMBER 是否阻塞其他会话(0=否,1=是) 快速定位阻塞源头

4.6.1 典型排查 SQL

以下 SQL 用于快速定位锁等待链:

-- 查询当前所有锁信息,包含会话信息
SELECT
  l.sid,
  l.type,
  l.id1,
  l.id2,
  l.lmode,
  l.request,
  l.block,
  l.ctime,
  s.username,
  s.osuser,
  s.program,
  s.sql_id,
  s.blocking_session
FROM v$lock l
JOIN v$session s ON l.sid = s.sid
WHERE l.type IN ('TX', 'TM')
ORDER BY l.block DESC, l.ctime DESC;
-- 查询被阻塞的会话及其等待的 SQL
SELECT
  wait.sid          AS waiting_sid,
  wait.username     AS waiting_user,
  wait.sql_id       AS waiting_sql,
  hold.sid          AS holding_sid,
  hold.username     AS holding_user,
  hold.sql_id       AS holding_sql,
  l.type,
  l.id1,
  l.id2,
  l.ctime           AS wait_seconds
FROM v$lock l
JOIN v$session wait ON l.sid = wait.sid
JOIN v$session hold ON wait.blocking_session = hold.sid
WHERE l.request > 0
  AND l.type IN ('TX', 'TM');
关键判断逻辑:
  • BLOCK = 1 且 LMODE > 0: 该会话持有锁并阻塞了其他会话,是阻塞源头。
  • REQUEST > 0 且 LMODE = 0: 该会话正在等待锁,是被阻塞方。
  • TYPE = 'TX' 且 ID1/ID2 相同: 多个会话等待同一事务锁,通常指向同一行数据。
v$lock 锁等待链排查流程 v$lock 锁等待链排查流程 1. 查询 v$lock 过滤 TYPE='TX'/'TM' 2. 定位 BLOCK=1 阻塞源头会话 3. 查等待会话 REQUEST > 0 4. 关联 v$session 获取 SQL / 用户 / 程序 5. 分析 ID1/ID2 判断是否同一行/对象 6. 定位阻塞 SQL v$session.sql_id 7. 决策处理 KILL SESSION / 通知业务 排查终点 确认阻塞源头 SQL → 评估是否可以终止会话或等待提交

4.7 锁等待排查实战要点

  • 优先检查 BLOCK 列: v$lock 中 BLOCK = 1 的会话是阻塞源头,应优先分析其正在执行的 SQL。
  • 区分 TX 与 TM 等待: TX 等待通常为行锁争用,TM 等待通常为 DDL 与 DML 冲突。
  • 关注 CTIME 列: 长时间(如 > 300 秒)未释放的锁,应评估是否需要手动终止会话。
  • 结合 v$session 的 BLOCKING_SESSION: Oracle 10g 以后,v$session.blocking_session 可直接显示阻塞会话 ID,简化排查。
  • 使用 v$locked_object: 快速定位被锁定的对象(表、行),关联 dba_objects 获取对象名。
生产环境操作提醒: 在确认阻塞源头后,如需终止会话,应使用 ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE,并提前通知业务方。切勿在未确认的情况下随意 kill 会话,以免导致事务回滚影响业务。