Oracle 的 TX、TM、UL 锁对比
Oracle 数据库中的这三种锁机制在并发控制中扮演着不同角色,以下是它们的对比分析:
一、基本特性对比
特性 | TX (事务锁) | TM (DML锁) | UL (用户锁) |
---|---|---|---|
锁类型 | 行级锁 | 表级锁 | 应用级自定义锁 |
作用范围 | 保护数据行变更 | 保护表结构不被修改 | 保护用户定义的资源 |
自动性 | 事务自动获取/释放 | DML语句自动获取/释放 | 需显式调用DBMS_LOCK获取 |
可见性 | 其他会话可见 | 其他会话可见 | 仅申请会话可见(默认) |
冲突检测 | 通过等待或死锁检测 | 立即冲突报错(ORA-00054) | 可配置等待或立即失败 |
二、技术实现对比
1. 数据结构差异
-
TX锁:
sql-- 在v$lock中的表示 TYPE='TX', ID1=USN.SLOT, ID2=WRAP# -- USN=undo段号,SLOT=槽位号,WRAP=序列号
-
TM锁:
sqlTYPE='TM', ID1=OBJECT_ID, ID2=0 -- 直接关联数据字典对象ID
-
UL锁:
sqlTYPE='UL', ID1=<lock_id>, ID2=0 -- lock_id由DBMS_LOCK.ALLOCATE_UNIQUE生成
2. 锁模式对比
模式 | TX锁表现 | TM锁表现 | UL锁表现 |
---|---|---|---|
共享(SS) | SELECT...FOR UPDATE | LOCK TABLE IN SHARE MODE | DBMS_LOCK.REQUEST(mode=>'S') |
排他(X) | UPDATE/DELETE操作 | LOCK TABLE IN EXCLUSIVE MODE | DBMS_LOCK.REQUEST(mode=>'X') |
空(N) | 事务结束释放 | 语句结束释放 | DBMS_LOCK.RELEASE调用 |
三、使用场景对比
1. TX锁典型场景
sql
-- 案例1:行级更新冲突
UPDATE employees SET salary=salary*1.1 WHERE emp_id=100;
-- 此时会在emp_id=100的记录上获得TX锁
-- 案例2:死锁场景
-- 会话1: UPDATE tableA SET... WHERE id=1;
-- 会话2: UPDATE tableB SET... WHERE id=2;
-- 会话1: UPDATE tableB SET... WHERE id=2; -- 等待
-- 会话2: UPDATE tableA SET... WHERE id=1; -- 死锁检测
2. TM锁典型场景
sql
-- 案例1:防止DDL与DML冲突
-- 会话1: SELECT * FROM orders FOR UPDATE;
-- 会话2: ALTER TABLE orders ADD column new_col NUMBER; -- 等待TM锁
-- 案例2:LOCK TABLE显式锁定
LOCK TABLE inventory IN EXCLUSIVE MODE;
3. UL锁典型场景
sql
-- 案例1:应用级资源协调
DECLARE
l_lockhandle VARCHAR2(128);
l_status NUMBER;
BEGIN
DBMS_LOCK.ALLOCATE_UNIQUE('APP_CONFIG_LOCK', l_lockhandle);
l_status := DBMS_LOCK.REQUEST(l_lockhandle, DBMS_LOCK.X_MODE);
IF l_status = 0 THEN
-- 执行需要互斥的操作
DBMS_LOCK.RELEASE(l_lockhandle);
END IF;
END;
四、诊断与问题处理
1. 锁等待分析
sql
-- 查看所有锁等待
SELECT
l1.sid holding_sid,
l2.sid waiting_sid,
l1.type lock_type,
CASE l1.type
WHEN 'TX' THEN '行锁/事务锁'
WHEN 'TM' THEN '表锁'
WHEN 'UL' THEN '用户锁'
END lock_desc,
s1.username holder,
s2.username waiter
FROM v$lock l1, v$lock l2, v$session s1, v$session s2
WHERE l1.block = 1
AND l2.request > 0
AND l1.id1 = l2.id1
AND l1.id2 = l2.id2
AND l1.sid = s1.sid
AND l2.sid = s2.sid;
2. 特殊问题处理
-
TX锁堆积:
sql-- 查找长事务 SELECT s.sid, s.serial#, s.username, s.status, t.start_time, t.used_ublk FROM v$transaction t, v$session s WHERE t.ses_addr = s.saddr ORDER BY t.used_ublk DESC;
-
TM锁冲突:
sql-- 查找被锁定的对象 SELECT object_name, object_type FROM dba_objects WHERE object_id = (SELECT id1 FROM v$lock WHERE type='TM' AND sid=&sid);
-
UL锁泄漏:
sql-- 检查未释放的用户锁 SELECT * FROM dba_lock_internal WHERE lock_type = 'UL' AND owner <> 'SYS';
五、性能优化建议
-
TX锁优化:
- 减少事务持续时间
- 使用
SELECT...FOR UPDATE NOWAIT
避免等待 - 适当增加
_TRANSACTION_TABLE_SIZE
参数
-
TM锁优化:
- 避免业务高峰期执行DDL
- 对大表DDL使用
ONLINE
选项 - 考虑使用
LOCK TABLE IN SHARE MODE
替代排他模式
-
UL锁最佳实践:
- 为锁命名使用前缀(如APPNAME_RESOURCE)
- 设置超时参数:
DBMS_LOCK.REQUEST(..., timeout=>10)
- 在异常处理中确保锁释放
六、版本差异说明
版本 | TX锁增强 | TM锁变化 | UL锁改进 |
---|---|---|---|
11g | 增加TX绑定特性 | 引入ONLINE DDL | 增加锁超时精确控制 |
12c | 支持IN_MEMORY事务 | 支持DDL等待超时 | 增加锁状态持久化选项 |
19c | 自适应死锁检测算法 | 减少索引维护的TM锁 | 支持PL/SQL锁监控视图 |
21c | 自动锁转换优化 | 分区表DDL锁粒度细化 | 增加全局UL锁命名空间 |
理解这三种锁的差异,可以帮助DBA更好地诊断并发问题并优化数据库性能。