DM8数据库采用多版本并发控制(MVCC)机制,兼顾并发性能与数据一致性,同时通过锁机制管控事务资源竞争。数据库事务执行DML(INSERT/UPDATE/DELETE)、SELECT … FOR UPDATE 语句时,会自动对数据行、表资源加锁,事务未提交/回滚前,锁资源不会释放。
在 DM8 的封锁机制中,核心由锁粒度(锁定对象)和锁模式(访问权限)两大相互独立又协同联动的子体系共同构成。两大体系各司其职、互为补充,共同规范了多事务并发场景下的数据锁定规则,有效规避脏读、幻读、数据覆盖等并发问题,保障数据库高效稳定运行。
锁模式用于控制多事务对同一锁定对象的并发访问规则,是判断阻塞、锁冲突的核心依据。DM8 标准锁模式共 4 种:意向共享锁(IS)、意向排他锁(IX)、共享锁(S)、排他锁(X),各模式标准定义如下:
不同事务之间锁兼容情况如下:
| 锁模式 | IS | S | IX | X |
|---|---|---|---|---|
| IS | 兼容 | 兼容 | 兼容 | 冲突 |
| S | 兼容 | 兼容 | 冲突 | 冲突 |
| IX | 兼容 | 冲突 | 兼容 | 冲突 |
| X | 冲突 | 冲突 | 冲突 | 冲突 |
锁粒度用于定义事务锁定的数据库对象范围,决定锁冲突范围与系统并发能力,粒度越精细,并发吞吐量越高。锁粒度分为:TID锁、对象锁、显示锁定表。
DM8 事务并发冲突主要分为普通锁等待(阻塞)与死锁两大类。其中锁等待(阻塞)可根据触发场景、锁粒度、业务表现细分为多种类型,包含 TID 记录锁等待、主键/唯一约束冲突等待、表级对象锁等待、数据字典锁等待等,各类场景特征、诱因、解决方案均不相同。
阻塞是单向锁等待场景:事务A持有某数据资源的锁且未提交,事务B需要竞争该资源的锁,无法获取资源则进入阻塞等待状态,持续挂起直至事务A释放锁(提交/回滚)。
阻塞是DM8数据库最常见的并发异常,由事务间锁模式不兼容引发单向资源等待,具备固定的故障特征与运行机制。
具体核心特点如下:
UPDATE / DELETE / INSERT 同一行,且前序事务未提交。示例:
##1. 会话 1 更新员工表 ID 为1004的工资到10000,该事务不提交
SQL> UPDATE DMHR.EMPLOYEE SET SALARY = 10000 where EMPLOYEE_ID=1004;
影响行数 1
SQL> <---未执行提交
##2. 会话 2 更新员工表 ID 为1004的部门ID为103
SQL> UPDATE DMHR.EMPLOYEE SET DEPARTMENT_ID = 104 where EMPLOYEE_ID=1004;
<---长时间处于执行状态,不访问状态
##3. 查询对应的锁状态
SQL> SELECT L.BLOCKED,L.LTYPE,L.LMODE,S.SQL_TEXT,S.STATE,S.TRX_ID FROM V$SESSIONS S JOIN V$LOCK L ON S.TRX_ID = L.TRX_ID WHERE L.LTYPE='TID';
行号 BLOCKED LTYPE LMODE SQL_TEXT STATE TRX_ID
---------- ----------- ----- ----- -------------------------------------------------------------------- ------ -------
1 1 TID X UPDATE DMHR.EMPLOYEE SET DEPARTMENT_ID = 104 where EMPLOYEE_ID=1004; ACTIVE 262754
2 0 TID X UPDATE DMHR.EMPLOYEE SET SALARY = 10000 where EMPLOYEE_ID=1004; IDLE 262753
PRIMARY KEY / UNIQUE 表插入相同键值,先执行的会话未提交,后执行的会话处于被阻塞状态。##1. 会话 1 向EMP表插入 ID 为8000的数据
SQL> insert into APP_USER.EMP(EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO) values(8000, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1250.00, 1400.00, 30);
影响行数 1
SQL> <---未执行提交
##2. 会话 2 向EMP表插入 ID 为8000的数据
SQL> insert into APP_USER.EMP(EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO) values(8000, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1250.00, 500.00, 30);
<---长时间处于执行状态,不返回执行结果
行号 BLOCKED LTYPE LMODE SQL_TEXT STATE TRX_ID
---------- ----------- ----- ----- ----------------------------------------------------------------------------------------------------------------------------------------------------------- ------ --------------------
1 1 TID X insert into APP_USER.EMP(EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO) values(8000, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1250.00, 500.00, 30); ACTIVE 262924
2 0 TID X insert into APP_USER.EMP(EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO) values(8000, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1250.00, 1400.00, 30); IDLE 262919
SELECT ... FOR UPDATE 语句引发锁冲突。示例:
##1. 会话 1 执行 for update语句
SQL> SELECT * FROM APP_USER.EMP FOR UPDATE;
##2. 会话 2 执行 insert语句,可以执行insert并进行提交
SQL> insert into APP_USER.EMP(EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO) values(8001, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1250.00, 1400.00, 30);
影响行数 1
SQL> commit;
操作已执行
##2. 会话 3 执行 delete 语句,该会话被阻塞
SQL> delete from APP_USER.EMP where EMPNO=7900;
<---长时间处于执行状态,不返回执行结果
ALTER TABLE / CREATE INDEX / DROP COLUMN 等 DDL。DDL_WAIT_TIME(默认 10s)控制,超时报锁超时,语句自动终止。示例:
##1. 会话 1 对 EMP 执行 insert 语句
SQL> insert into APP_USER.EMP(EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO) values(8002, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1250.00, 1400.00, 30);
影响行数 1
SQL> <--不进行提交
##2. 会话 1 对 EMP 表创建索引
SQL> create index APP_USER.IDX_ENAME on APP_USER.EMP(ENAME) ;
<--长时间执行,不返回结果,超过 DDL_WAIT_TIME 时间后,报锁超时后,自动终止
执行失败(语句1)
-6407: 锁超时
示例:
##1. 会话 1 对 BIGTAB 添加 C1 列并增加默认值
SQL> ALTER TABLE APP_USER.BIGTAB ADD COLUMN c1 INT DEFAULT 0;
##2. 会话 2 对 BIGTAB 更新操作
SQL> SQL> UPDATE APP_USER.BIGTAB SET name='x' WHERE id=1;
<--长时间执行,不返回结果,等待 DDL 语句执行完成释放锁后,才执行成功
影响行数 3
针对各类单向锁等待阻塞场景,优先从事务规范、运维规范等方向入手。日常需严格控制事务生命周期,杜绝长事务驻留;运维操作主动规避业务高峰,严格隔离DDL与DML并发执行场景。出现阻塞故障时,可通过系统视图快速定位阻塞源头,联动业务确认事务状态,督促完成事务提交或回滚并优化整改对应业务逻辑;紧急故障场景可强制终止阻塞会话,快速恢复业务正常。
死锁是双向循环锁等待场景:两个或多个事务互相持有对方需要的锁资源,同时互相等待对方释放锁,形成闭环依赖,所有事务永久阻塞。
死锁是数据库极端的并发锁异常,由多事务资源循环竞争、锁依赖闭环引发,具备区别于普通阻塞的独有故障特征与数据库处理机制。
具体核心特点如下:
[-6403]: 死锁,业务侧可捕获该异常;死锁等待,数据库层面只能被动处理,无法根治,必须依赖业务优化。统一多资源、多表、多记录的更新执行顺序,彻底消除循环锁依赖;拆分复杂大事务,精简事务内执行逻辑,最大限度缩短锁持有时长;业务代码捕获 [-6403]:死锁 异常,增加自动重试机制提升容错性;事后通过死锁历史视图溯源问题SQL,迭代优化事务并发逻辑。
结合锁机制原理,阻塞与死锁均为事务锁不兼容引发的并发故障,但二者在等待逻辑、数据库处理机制、业务影响、解决方式上存在本质区别,两者的差异如下:
| 对比维度 | 阻塞(锁等待) | 死锁 |
|---|---|---|
| 等待方式 | 单向等待 | 循环双向等待 |
| 自动恢复 | 无法自动恢复 | 数据库自动检测、自动破除 |
| 业务影响 | 事务卡顿、连接堆积、服务超时 | 事务直接失败、业务报错 |
| 核心诱因 | 长事务、锁范围过大 | SQL执行顺序交叉、事务逻辑混乱 |
DM8提供多张系统动态视图,可实时查询锁状态、阻塞关系、死锁历史、会话事务信息,是故障排查的核心工具。
以下为常用核心视图:
| 视图名称 | 分类 | 核心用途 | 关键字段 |
|---|---|---|---|
| V$LOCK | 锁资源 | 实时查询活动的事务锁信息,包含锁类型、事务ID、阻塞状态 | TRX_ID, LTYPE, LMODE, BLOCKED, TABLE_ID, TID |
| V$SESSIONS | 会话信息 | 查询在线会话、执行SQL、事务状态、客户端地址等会话级信息 | SESS_ID, SQL_TEXT, TRX_ID,STATE |
| V$TRX | 事务信息 | 查询活跃事务、事务开启时间、锁持有数量等事务级信息 | ID, STATUS,SESS_ID |
| V$TRXWAIT | 事务等待 | 精准展示阻塞等待关系,定位等待事务与阻塞源头事务 | TRX_ID, WAIT_FOR_ID |
| V$DEADLOCK_HISTORY | 死锁历史 | 留存历史死锁详情,用于事后溯源分析与问题定位 | TRX_ID,SESS_ID,SQL_TEXT,HAPPEN_TIME,DEADLOCK_CYCLE |
| V$SQL_HISTORY | SQL历史 | 记录历史执行的SQL语句,用于事后溯源、慢SQL排查与性能分析。默认保留最近10000条数据,由SQL_HISTORY_CNT 参数控制,最大保留100000 条记录 |
SEQ_NO,SESS_ID,TRX_ID,TOP_SQL_TEXT,START_TIME |
SELECT
DATEDIFF(SS, S1.LAST_SEND_TIME, SYSDATE) WAIT_TIME_S,
'被阻塞的信息' WAIT_INFO,
S1.SESS_ID WAIT_SID,
S1.SQL_TEXT WAIT_SQL_TEXT,
S1.STATE WAIT_STATE,
S1.TRX_ID WAIT_TRX_ID,
S1.USER_NAME WAIT_USER_NAME,
S1.CLNT_IP WAIT_CLNT_IP,
S1.APPNAME WAIT_APPNAME,
S1.LAST_SEND_TIME WAIT_LAST_SEND_TIME,
'SP_CLOSE_SESSION(' || S1.SESS_ID || ');' KILL_WAIT_SID,
'引起阻塞的信息' BLOCK,
S2.SESS_ID BLOCK_SID,
S2.SQL_TEXT BLOCK_SQL_TEXT,
S2.STATE BLOCK_STATE,
S2.TRX_ID BLOCK_TRX_ID,
S2.USER_NAME BLOCK_USER_NAME,
S2.CLNT_IP BLOCK_CLNT_IP,
S2.APPNAME BLOCK_APPNAME,
S2.LAST_SEND_TIME BLOCK_LAST_SEND_TIME,
'SP_CLOSE_SESSION(' || S2.SESS_ID || ');' KILL_BLOCK_SID
FROM
V$SESSIONS S1, V$SESSIONS S2, V$TRXWAIT W
WHERE
S1.TRX_ID = W.ID
AND
S2.TRX_ID = W.WAIT_FOR_ID;
通过锁阻塞排查语句获取到的阻塞结果,通常分为两种场景:
行号 WAIT_TIME_S WAIT_INFO WAIT_SID WAIT_SQL_TEXT WAIT_STATE WAIT_TRX_ID WAIT_USER_NAME WAIT_CLNT_IP WAIT_APPNAME WAIT_LAST_SEND_TIME KILL_WAIT_SID BLOCK BLOCK_SID BLOCK_SQL_TEXT BLOCK_STATE BLOCK_TRX_ID BLOCK_USER_NAME BLOCK_CLNT_IP BLOCK_APPNAME BLOCK_LAST_SEND_TIME KILL_BLOCK_SID
---------- ----------- ------------------ -------------------- ------------------------------------------- ---------- -------------------- -------------- -------------------------- ------------ -------------------------- ---------------------------------- --------------------- -------------------- ----------------------------------------------------- ----------- -------------------- --------------- ------------------------- ------------- -------------------------- ----------------------------------
1 64 被阻塞的信息 139953070740384 delete from app_user.emp where empno=7902; ACTIVE 274598 SYSDBA ::ffff:192.168.56.13:51200 disql 2026-08-07 11:23:13.784807 SP_CLOSE_SESSION(139953070740384); 引起阻塞的信息 139953070300696 update app_user.emp set sal=14600 where empno=7902; IDLE 274597 SYSDBA ::ffff:192.168.56.1:61189 DIsql.exe 2026-08-07 11:23:50.067220 SP_CLOSE_SESSION(139953070300696);
行号 WAIT_TIME_S WAIT_INFO WAIT_SID WAIT_SQL_TEXT WAIT_STATE WAIT_TRX_ID WAIT_USER_NAME WAIT_CLNT_IP WAIT_APPNAME WAIT_LAST_SEND_TIME KILL_WAIT_SID BLOCK BLOCK_SID BLOCK_SQL_TEXT BLOCK_STATE BLOCK_TRX_ID BLOCK_USER_NAME BLOCK_CLNT_IP BLOCK_APPNAME BLOCK_LAST_SEND_TIME KILL_BLOCK_SID
---------- ----------- ------------------ -------------------- ------------------------------------------- ---------- -------------------- -------------- -------------------------- ------------ -------------------------- ---------------------------------- --------------------- -------------------- ------------------------------------------------ ----------- -------------------- --------------- ------------------------- ------------- -------------------------- ----------------------------------
1 125 被阻塞的信息 139953070740384 delete from app_user.emp where empno=7902; ACTIVE 274598 SYSDBA ::ffff:192.168.56.13:51200 disql 2026-08-07 11:23:13.784807 SP_CLOSE_SESSION(139953070740384); 引起阻塞的信息 139953070300696 select ENAME FROM app_user.emp where empno=7902; IDLE 274597 SYSDBA ::ffff:192.168.56.1:61189 DIsql.exe 2026-08-07 11:25:12.710349 SP_CLOSE_SESSION(139953070300696);
V$SQL_HISTORY 内存视图(保留记录条数可参考【锁处理相关视图】关于该视图的说明)内,我们便可查询该视图,检索该阻塞会话完整的 SQL 执行记录,定位出最先占用行锁、引发阻塞的原始语句;SQL> SELECT START_TIME,SESS_ID,TRX_ID,TOP_SQL_TEXT from V$SQL_HISTORY WHERE TRX_ID=274597 AND SESS_ID=139953070300696 ORDER BY START_TIME ASC;
行号 START_TIME SESS_ID TRX_ID TOP_SQL_TEXT
---------- -------------------------- ------------------ ------- -----------------------------------------------------
1 2026-08-07 11:23:50.066883 139953070300696 274597 update app_user.emp set sal=14600 where empno=7902;
2 2026-08-07 11:25:12.710306 139953070300696 274597 select ENAME FROM app_user.emp where empno=7902;
V$SQL_HISTORY 的缓存保存周期,内存视图的数据已经覆盖,这时就需要依靠 SQL 日志进行溯源。需要注意 SQLLOG 日志不会默认开启,想要留存完整的执行语句,必须事前开启数据库 SQL 日志采集功能。##根据查询出的事务ID 274597 ,查找SQLLOG日志相关内容
[dmdba@dm8 dmlogcommit]$ cat dmsql_DMSERVER_20260807_112122.log |grep 274597
2026-08-07 11:23:50.065 (EP[0] sess:0x7f495d0a5e18 thrd:2864 user:SYSDBA trxid:274597 stmt:NULL appname:DIsql.exe ip:::ffff:192.168.56.1) TRX: START
2026-08-07 11:23:50.069 (EP[0] sess:0x7f495d0a5e18 thrd:2864 user:SYSDBA trxid:274597 stmt:0x7f495d16ced0 appname:DIsql.exe ip:::ffff:192.168.56.1) [UPD] update app_user.emp set sal=14600 where empno=7902;
2026-08-07 11:23:50.069 (EP[0] sess:0x7f495d0a5e18 thrd:2864 user:SYSDBA trxid:274597 stmt:0x7f495d16ced0 appname:DIsql.exe ip:::ffff:192.168.56.1) DLCK used time:3(us)
2026-08-07 11:23:50.069 (EP[0] sess:0x7f495d0a5e18 thrd:2864 user:SYSDBA trxid:274597 stmt:NULL appname:DIsql.exe ip:::ffff:192.168.56.1) trx[274597] alloc pseg page[0, 2015], page_lsn[1465964], n_pages[1]
2026-08-07 11:23:50.069 (EP[0] sess:0x7f495d0a5e18 thrd:2864 user:SYSDBA trxid:274597 stmt:0x7f495d16ced0 appname:DIsql.exe ip:::ffff:192.168.56.1) [UPD] update app_user.emp set sal=14600 where empno=7902; EXECTIME: 0(ms) ROWCOUNT: 1(rows) EXEC_ID: 601.
2026-08-07 11:25:12.713 (EP[0] sess:0x7f495d0a5e18 thrd:2864 user:SYSDBA trxid:274597 stmt:0x7f495d16ced0 appname:DIsql.exe ip:::ffff:192.168.56.1) PREPARE
2026-08-07 11:25:12.713 (EP[0] sess:0x7f495d0a5e18 thrd:2864 user:SYSDBA trxid:274597 stmt:0x7f495d16ced0 appname:DIsql.exe ip:::ffff:192.168.56.1) [ORA]: select ENAME FROM app_user.emp where empno=7902;
2026-08-07 11:25:12.713 (EP[0] sess:0x7f495d0a5e18 thrd:2864 user:SYSDBA trxid:274597 stmt:0x7f495d16ced0 appname:DIsql.exe ip:::ffff:192.168.56.1) [SEL] select ENAME FROM app_user.emp where empno=7902;
2026-08-07 11:25:12.713 (EP[0] sess:0x7f495d0a5e18 thrd:2864 user:SYSDBA trxid:274597 stmt:0x7f495d16ced0 appname:DIsql.exe ip:::ffff:192.168.56.1) DLCK used time:1(us)
2026-08-07 11:25:12.713 (EP[0] sess:0x7f495d0a5e18 thrd:2864 user:SYSDBA trxid:274597 stmt:0x7f495d16ced0 appname:DIsql.exe ip:::ffff:192.168.56.1) [SEL] select ENAME FROM app_user.emp where empno=7902; EXECTIME: 0(ms) ROWCOUNT: 1(rows) EXEC_ID: 602.
可参考如下步骤开启SQLLOG日志:
##1. 编辑SQLLOG配置文件,该文件位于数据库数据目录内 [dmdba@dm8 DAMENG]$ vi sqllog.ini [SLOG_ALL] FILE_PATH = /dmbak/dmlogcommit ## SQL日志存放目录 SWITCH_LIMIT = 128 ## 单个日志文件上限,单位 MB;到达128MB自动新建日志 ASYNC_FLUSH = 1 ## 0 同步刷盘,SQL执行完毕立刻落盘,性能偏低、数据最安全 ## 1 异步刷盘,缓冲区批量写入磁盘,减少IO损耗,生产环境推荐 FILE_NUM = 100 ## 日志文件最大保留份数;超出100个,自动删除最老旧的SQL日志文件 ##2. 数据库开启 SQLLOG 日志功能 SQL> SP_SET_PARA_VALUE(2,'SVR_LOG',1); DMSQL 过程已成功完成 ##3. 重启数据库使配置生效
SQL> SP_CLOSE_SESSION(139953070300696); DMSQL 过程已成功完成
达梦内置视图 V$LOCK、V$TRXWAIT 只负责展示当下时刻的锁资源与事务等待状态,属于瞬时内存视图;一旦事务提交、会话断开,阻塞链路信息随即释放。
因此如果需要事后回查曾经发生过的锁阻塞、定位历史阻塞源头、阻塞 SQL 以及等待链路,必须提前配置定时 JOB 任务,周期性采样抓取阻塞会话、事务 ID、客户端 IP、正在执行语句、锁类型等字段,持久化存入自建日志数据表,方便故障发生之后回查分析。
--查询 TRX_WAIT_HISTORY 内容,查看历史阻塞信息
SQL> SELECT WAIT_INFO,WAIT_SID,WAIT_SQL_TEXT,WAIT_TRX_ID,BLOCK_INFO,BLOCK_SID,BLOCK_SQL_TEXT,BLOCK_TRX_ID from TRX_WAIT_HISTORY WHERE WAIT_TRX_ID=274598;
行号 WAIT_INFO WAIT_SID WAIT_SQL_TEXT WAIT_TRX_ID BLOCK_INFO BLOCK_SID BLOCK_SQL_TEXT BLOCK_TRX_ID
---------- ------------------ -------------------- ------------------------------------------- -------------------- --------------------- -------------------- ------------------------------------------------ --------------------
1 被阻塞的信息 139953070740384 delete from app_user.emp where empno=7902; 274598 引起阻塞的信息 139953070300696 select ENAME FROM app_user.emp where empno=7902; 274597
可参考如下内容,创建定时作业获取数据库阻塞信息并记录:
--代理作业设置后,随着表记录增加,表占用空间会逐渐增加,需注意及时清理历史信息
--1. 创建阻塞信息记录表
CREATE TABLE TRX_WAIT_HISTORY
(
STATTIME TIMESTAMP,
WAIT_TIME_S INTEGER,
WAIT_INFO VARCHAR2(30),
WAIT_SID BIGINT,
WAIT_SQL_TEXT VARCHAR(1000),
WAIT_STATE VARCHAR(10),
WAIT_TRX_ID BIGINT,
WAIT_USER_NAME VARCHAR(128),
WAIT_CLNT_IP VARCHAR(128),
WAIT_APPNAME VARCHAR(128),
WAIT_LAST_SEND_TIME DATETIME(6),
BLOCK_INFO VARCHAR2(30),
BLOCK_SID BIGINT,
BLOCK_SQL_TEXT VARCHAR(1000),
BLOCK_STATE VARCHAR(10),
BLOCK_TRX_ID BIGINT,
BLOCK_USER_NAME VARCHAR(128),
BLOCK_CLNT_IP VARCHAR(128),
BLOCK_APPNAME VARCHAR(128),
BLOCK_LAST_SEND_TIME DATETIME(6)
);
--2. 创建存储过程获取阻塞信息并插入到阻塞信息记录表
CREATE PROCEDURE GET_TRX_WAIT
AS
BEGIN
INSERT INTO TRX_WAIT_HISTORY
SELECT SYSDATE STATTIME,
DATEDIFF(SS, S1.LAST_SEND_TIME, SYSDATE) WAIT_TIME_S,
'被阻塞的信息' WAIT_INFO,
S1.SESS_ID WAIT_SID,
S1.SQL_TEXT WAIT_SQL_TEXT,
S1.STATE WAIT_STATE,
S1.TRX_ID WAIT_TRX_ID,
S1.USER_NAME WAIT_USER_NAME,
S1.CLNT_IP WAIT_CLNT_IP,
S1.APPNAME WAIT_APPNAME,
S1.LAST_SEND_TIME WAIT_LAST_SEND_TIME,
'引起阻塞的信息' BLOCK_INFO,
S2.SESS_ID BLOCK_SID,
S2.SQL_TEXT BLOCK_SQL_TEXT,
S2.STATE BLOCK_STATE,
S2.TRX_ID BLOCK_TRX_ID,
S2.USER_NAME BLOCK_USER_NAME,
S2.CLNT_IP BLOCK_CLNT_IP,
S2.APPNAME BLOCK_APPNAME,
S2.LAST_SEND_TIME BLOCK_LAST_SEND_TIME
FROM V$SESSIONS S1,
V$SESSIONS S2,
V$TRXWAIT W
WHERE S1.TRX_ID = W.ID
AND S2.TRX_ID = W.WAIT_FOR_ID;
COMMIT;
END;
--3. 通过代理作业,设置每 1 分钟获取一次阻塞信息
--3.1 如未初始化代理作业,需要先初始化代理作业
SQL>SP_INIT_JOB_SYS(1);
--3.2 设置每1分钟执行一次 GET_TRX_WAIT 存储过程获取阻塞信息
call SP_CREATE_JOB('GET_TRXWAIT_1MIN',1,0,'',0,0,'',0,'');
call SP_JOB_CONFIG_START('GET_TRXWAIT_1MIN');
call SP_ADD_JOB_STEP_EX('GET_TRXWAIT_1MIN', 'GET_TRXWAIT', 0, 'GET_TRX_WAIT', 1, 1, 0, 0, NULL, 0, '');
call SP_ADD_JOB_SCHEDULE('GET_TRXWAIT_1MIN', 'GET_TRX_WAIT_1MIN', 1, 1, 1, 0, 1, '00:00:00', '23:59:59', '2026-08-07 00:00:00', NULL, '');
call SP_JOB_CONFIG_COMMIT('GET_TRXWAIT_1MIN');
--3.3 如有需要可选择参考如下语句,修改代理作业每 2 分钟执行一次 GET_TRX_WAIT 存储过程获取阻塞信息
call SP_JOB_CONFIG_START('GET_TRXWAIT_1MIN');
call SP_ALTER_JOB_SCHEDULE('GET_TRXWAIT_1MIN', 'GET_TRX_WAIT_1MIN', 1, 1, 1, 0, 2, '00:00:00', '23:59:59', '2026-08-07 00:00:00', NULL, '');
call SP_JOB_CONFIG_COMMIT('GET_TRXWAIT_1MIN');
数据库具备自动死锁检测能力,检测到循环等待之后会主动牺牲回滚其中一个事务,快速断开死锁阻塞,防止会话长时间僵持等待;所有历史死锁事件都会留存至 V$DEADLOCK_HISTORY,可通过该视图完成事后故障溯源。
SQL> select TRX_ID,SESS_ID,SQL_TEXT,HAPPEN_TIME,DEADLOCK_CYCLE from SYS.V$DEADLOCK_HISTORY order by SEQNO asc;
行号 TRX_ID SESS_ID SQL_TEXT HAPPEN_TIME DEADLOCK_CYCLE
---------- -------------------- -------------------- -------------------------------------------------------------------------------- -------------------------- -----------------------------------------
1 281496 140710860375712 UPDATE DMHR.DEPARTMENT SET DEPARTMENT_NAME='市场部' WHERE DEPARTMENT_ID=1002; 2026-08-07 14:32:49.257775 self -> (281499, 140710694690984) -> self
V$SQL_HISTORY表,查看死锁SQL信息SQL> SELECT H.SEQ_NO,H.SESS_ID,H.TRX_ID,H.TOP_SQL_TEXT,H.START_TIME from SYS.V$SQL_HISTORY H WHERE H.TRX_ID IN (281496,281499) ORDER BY H.START_TIME ASC;
行号 SEQ_NO SESS_ID TRX_ID TOP_SQL_TEXT START_TIME
---------- ----------- -------------------- -------------------- -------------------------------------------------------------------------------------- --------------------------
1 670 140710860375712 281496 UPDATE DMHR.EMPLOYEE SET SALARY = 12000 WHERE EMPLOYEE_ID=1002; 2026-08-07 14:32:09.560017
2 672 140710694690984 281499 UPDATE DMHR.DEPARTMENT SET LOCATION_ID = 11 WHERE MANAGER_ID = 10002; 2026-08-07 14:32:24.090754
3 673 140710694690984 281499 UPDATE DMHR.EMPLOYEE SET DEPARTMENT_ID = 101 WHERE IDENTITY_CARD='630103197612261000'; 2026-08-07 14:32:41.250372
4 674 140710860375712 281496 UPDATE DMHR.DEPARTMENT SET DEPARTMENT_NAME='市场部' WHERE DEPARTMENT_ID=1002; 2026-08-07 14:32:48.501083
5 675 140710860375712 281496 commit; 2026-08-07 14:32:55.718433
6 676 140710694690984 281499 commit; 2026-08-07 14:32:59.723992
V$SQL_HISTORY表保留记录,可通过 SQLLOG 日志查询相关记录--1. 事务 281496 的信息,可以看到死锁信息 [ERR(-6403)]: UPDATE DMHR.DEPARTMENT SET DEPARTMENT_NAME='市场部' WHERE DEPARTMENT_ID=1002;
[dmdba@dm8 dmlogcommit]$ cat dmsql_DMSERVER_20260807_132900.log|grep 281496
2026-08-07 14:32:09.563 (EP[0] sess:0x7ff9ccd946a0 thrd:2709 user:SYSDBA trxid:281496 stmt:NULL appname:disql ip:::1) TRX: START
2026-08-07 14:32:09.563 (EP[0] sess:0x7ff9ccd946a0 thrd:2709 user:SYSDBA trxid:281496 stmt:0x7ff9cd4cd238 appname:disql ip:::1) [UPD] UPDATE DMHR.EMPLOYEE SET SALARY = 12000 WHERE EMPLOYEE_ID=1002;
2026-08-07 14:32:09.563 (EP[0] sess:0x7ff9ccd946a0 thrd:2709 user:SYSDBA trxid:281496 stmt:0x7ff9cd4cd238 appname:disql ip:::1) DLCK used time:1(us)
2026-08-07 14:32:09.571 (EP[0] sess:0x7ff9ccd946a0 thrd:2709 user:SYSDBA trxid:281496 stmt:NULL appname:disql ip:::1) trx[281496] alloc pseg page[0, 1887], page_lsn[1468561], n_pages[1]
2026-08-07 14:32:09.571 (EP[0] sess:0x7ff9ccd946a0 thrd:2709 user:SYSDBA trxid:281496 stmt:0x7ff9cd4cd238 appname:disql ip:::1) [UPD] UPDATE DMHR.EMPLOYEE SET SALARY = 12000 WHERE EMPLOYEE_ID=1002; EXECTIME: 4(ms) ROWCOUNT: 1(rows) EXEC_ID: 10801.
2026-08-07 14:32:48.503 (EP[0] sess:0x7ff9ccd946a0 thrd:2709 user:SYSDBA trxid:281496 stmt:0x7ff9cd4cd238 appname:disql ip:::1) PREPARE
2026-08-07 14:32:48.503 (EP[0] sess:0x7ff9ccd946a0 thrd:2709 user:SYSDBA trxid:281496 stmt:0x7ff9cd4cd238 appname:disql ip:::1) [ORA]: UPDATE DMHR.DEPARTMENT SET DEPARTMENT_NAME='市场部' WHERE DEPARTMENT_ID=1002;
2026-08-07 14:32:48.507 (EP[0] sess:0x7ff9ccd946a0 thrd:2709 user:SYSDBA trxid:281496 stmt:0x7ff9cd4cd238 appname:disql ip:::1) [UPD] UPDATE DMHR.DEPARTMENT SET DEPARTMENT_NAME='市场部' WHERE DEPARTMENT_ID=1002;
2026-08-07 14:32:48.507 (EP[0] sess:0x7ff9ccd946a0 thrd:2709 user:SYSDBA trxid:281496 stmt:0x7ff9cd4cd238 appname:disql ip:::1) DLCK used time:1(us)
2026-08-07 14:32:49.263 (EP[0] sess:0x7ff9ccd946a0 thrd:2709 user:SYSDBA trxid:281496 stmt:NULL appname:disql ip:::1) trx[281496] LOCK_TID (mode:X, table id:1050) wait for 1 trxs, trx[281499] used time:757(ms)
2026-08-07 14:32:49.263 (EP[0] sess:0x7ff9ccd946a0 thrd:2709 user:SYSDBA trxid:281496 stmt:0x7ff9cd4cd238 appname:disql ip:::1) [ERR(-6403)]: UPDATE DMHR.DEPARTMENT SET DEPARTMENT_NAME='市场部' WHERE DEPARTMENT_ID=1002; EXECTIME: 757(ms) ROWCOUNT: 0(rows) EXEC_ID: 10802.
2026-08-07 14:32:55.723 (EP[0] sess:0x7ff9ccd946a0 thrd:2709 user:SYSDBA trxid:281496 stmt:0x7ff9cd4cd238 appname:disql ip:::1) PREPARE
2026-08-07 14:32:55.723 (EP[0] sess:0x7ff9ccd946a0 thrd:2709 user:SYSDBA trxid:281496 stmt:0x7ff9cd4cd238 appname:disql ip:::1) [ORA]: commit;
2026-08-07 14:32:55.723 (EP[0] sess:0x7ff9ccd946a0 thrd:2709 user:SYSDBA trxid:281496 stmt:0x7ff9cd4cd238 appname:disql ip:::1) [DML] commit;
2026-08-07 14:32:55.723 (EP[0] sess:0x7ff9ccd946a0 thrd:2709 user:SYSDBA trxid:281496 stmt:NULL appname:disql ip:::1) TRX: COMMIT
2026-08-07 14:32:55.720 (EP[0] sess:0x7ff9c2f920a8 thrd:2709 user:SYSDBA trxid:281499 stmt:NULL appname:DIsql.exe) trx[281499] LOCK_TID (mode:X, table id:1052) wait for 1 trxs, trx[281496] used time:14469(ms)
2026-08-07 14:34:56.131 (EP[0] sess:NULL thrd:NULL user:NULL trxid:NULL stmt:NULL) trx[281496]: purg2_page free pseg page( 0, 1887), page_lsn =1468623
[dmdba@dm8 dmlogcommit]$
--2. 事务 281499 的信息
[dmdba@dm8 dmlogcommit]$ cat dmsql_DMSERVER_20260807_132900.log |grep 281499
2026-08-07 14:32:24.084 (EP[0] sess:0x7ff9c2f920a8 thrd:2710 user:SYSDBA trxid:281499 stmt:NULL appname:DIsql.exe ip:::ffff:192.168.56.1) TRX: START
2026-08-07 14:32:24.084 (EP[0] sess:0x7ff9c2f920a8 thrd:2710 user:SYSDBA trxid:281499 stmt:0x7ff9ccacd0f0 appname:DIsql.exe ip:::ffff:192.168.56.1) [UPD] UPDATE DMHR.DEPARTMENT SET LOCATION_ID = 11 WHERE MANAGER_ID = 10002;
2026-08-07 14:32:24.084 (EP[0] sess:0x7ff9c2f920a8 thrd:2710 user:SYSDBA trxid:281499 stmt:0x7ff9ccacd0f0 appname:DIsql.exe ip:::ffff:192.168.56.1) DLCK used time:2(us)
2026-08-07 14:32:24.084 (EP[0] sess:0x7ff9c2f920a8 thrd:2710 user:SYSDBA trxid:281499 stmt:NULL appname:DIsql.exe ip:::ffff:192.168.56.1) trx[281499] alloc pseg page[0, 2447], page_lsn[1468575], n_pages[1]
2026-08-07 14:32:24.084 (EP[0] sess:0x7ff9c2f920a8 thrd:2710 user:SYSDBA trxid:281499 stmt:0x7ff9ccacd0f0 appname:DIsql.exe ip:::ffff:192.168.56.1) [UPD] UPDATE DMHR.DEPARTMENT SET LOCATION_ID = 11 WHERE MANAGER_ID = 10002; EXECTIME: 0(ms) ROWCOUNT: 1(rows) EXEC_ID: 11101.
2026-08-07 14:32:41.240 (EP[0] sess:0x7ff9c2f920a8 thrd:2710 user:SYSDBA trxid:281499 stmt:0x7ff9ccacd0f0 appname:DIsql.exe ip:::ffff:192.168.56.1) PREPARE
2026-08-07 14:32:41.240 (EP[0] sess:0x7ff9c2f920a8 thrd:2710 user:SYSDBA trxid:281499 stmt:0x7ff9ccacd0f0 appname:DIsql.exe ip:::ffff:192.168.56.1) [ORA]: UPDATE DMHR.EMPLOYEE SET DEPARTMENT_ID = 101 WHERE IDENTITY_CARD='630103197612261000';
2026-08-07 14:32:41.248 (EP[0] sess:0x7ff9c2f920a8 thrd:2710 user:SYSDBA trxid:281499 stmt:0x7ff9ccacd0f0 appname:DIsql.exe ip:::ffff:192.168.56.1) [UPD] UPDATE DMHR.EMPLOYEE SET DEPARTMENT_ID = 101 WHERE IDENTITY_CARD='630103197612261000';
2026-08-07 14:32:41.248 (EP[0] sess:0x7ff9c2f920a8 thrd:2710 user:SYSDBA trxid:281499 stmt:0x7ff9ccacd0f0 appname:DIsql.exe ip:::ffff:192.168.56.1) DLCK used time:2(us)
2026-08-07 14:32:49.263 (EP[0] sess:0x7ff9ccd946a0 thrd:2709 user:SYSDBA trxid:281496 stmt:NULL appname:disql ip:::1) trx[281496] LOCK_TID (mode:X, table id:1050) wait for 1 trxs, trx[281499] used time:757(ms)
2026-08-07 14:32:55.720 (EP[0] sess:0x7ff9c2f920a8 thrd:2709 user:SYSDBA trxid:281499 stmt:NULL appname:DIsql.exe) trx[281499] LOCK_TID (mode:X, table id:1052) wait for 1 trxs, trx[281496] used time:14469(ms)
2026-08-07 14:32:55.716 (EP[0] sess:0x7ff9c2f920a8 thrd:2710 user:SYSDBA trxid:281499 stmt:0x7ff9ccacd0f0 appname:DIsql.exe ip:::ffff:192.168.56.1) DLCK used time:6(us)
2026-08-07 14:32:55.716 (EP[0] sess:0x7ff9c2f920a8 thrd:2710 user:SYSDBA trxid:281499 stmt:0x7ff9ccacd0f0 appname:DIsql.exe ip:::ffff:192.168.56.1) [UPD] UPDATE DMHR.EMPLOYEE SET DEPARTMENT_ID = 101 WHERE IDENTITY_CARD='630103197612261000'; EXECTIME: 14470(ms) ROWCOUNT: 1(rows) EXEC_ID: 11102.
2026-08-07 14:32:59.720 (EP[0] sess:0x7ff9c2f920a8 thrd:2710 user:SYSDBA trxid:281499 stmt:0x7ff9ccacd0f0 appname:DIsql.exe ip:::ffff:192.168.56.1) PREPARE
2026-08-07 14:32:59.720 (EP[0] sess:0x7ff9c2f920a8 thrd:2710 user:SYSDBA trxid:281499 stmt:0x7ff9ccacd0f0 appname:DIsql.exe ip:::ffff:192.168.56.1) [ORA]: commit;
2026-08-07 14:32:59.720 (EP[0] sess:0x7ff9c2f920a8 thrd:2710 user:SYSDBA trxid:281499 stmt:0x7ff9ccacd0f0 appname:DIsql.exe ip:::ffff:192.168.56.1) [DML] commit;
2026-08-07 14:32:59.720 (EP[0] sess:0x7ff9c2f920a8 thrd:2710 user:SYSDBA trxid:281499 stmt:NULL appname:DIsql.exe ip:::ffff:192.168.56.1) TRX: COMMIT
2026-08-07 14:35:00.136 (EP[0] sess:NULL thrd:NULL user:NULL trxid:NULL stmt:NULL) trx[281499]: purg2_page free pseg page( 0, 2447), page_lsn =1468624
[dmdba@dm8 dmlogcommit]$
文章
阅读量
获赞
