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) 实现,等待会话会挂在持有会话的链表上,形成等待链。
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 相同: 多个会话等待同一事务锁,通常指向同一行数据。
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 会话,以免导致事务回滚影响业务。