Oracle死锁问题: enq: TX - row lock contention

article/2025/8/28 11:47:52

 


前言


       这篇文章也是记录近期遇到的问题以及从中学到的知识 ,近期一直在救火,有些问题自认为还是挺有代表性的,有兴趣的话再继续向下看


问题现象


       线上反馈,执行批量处理EXCEL数据时,系统一直卡在进度滚动条界面。处理任务等了一个多小时也没有完成。起初,看到售后反馈这个问题时我很惊讶, 因为在这前一天,我还帮另一位售后完成了相同的处理操作。怎么隔一天就出问题了 。我习惯性的觉得操作员又弄错了配置或者又把数据填错了,处理这类问题是最让开发人员恼火的事情。

      一般系统问题分两类, 要么是程序问题要么是数据问题, 找到售后拿到了问题视频记录, 看到传回来的视频发现售后人员操作满足流程要求,没有错误, 又核实了EXCEL模板并检查模板数据,最后排查代码也没有发现明显问题, 这就不好办了


问题分析


1. 系统中发现死锁

         正当自己纠结的时候,售后告知问题复现, 能复现问题,那么就好解决了, 查询了下栈信息,发现系统多线程数据处理的时候都卡在了1条UPDATE语句上,堆栈信息如下。 (如果查看栈信息, 可参考另一篇文章 传送门:JVM记 jstack命令的时候报错Unable to open socket file)

"pool-91-thread-1" prio=6 tid=0x53116800 nid=0x3bc8 in Object.wait() [0x51b2f000]java.lang.Thread.State: TIMED_WAITING (on object monitor)at java.lang.Object.wait(Native Method)at com.star.sms.batch.TransactionGuarded.doHold(TransactionGuarded.java:75)at com.star.sms.batch.TransactionGuarded.hold(TransactionGuarded.java:60)- locked <0x32269c70> (a com.star.sms.batch.TransactionGuarded)at com.star.sms.batch.AbstractBatchAcceptTask.processByGuarded(AbstractBatchAcceptTask.java:112)at com.star.sms.batch.AbstractBatchAcceptTask.call(AbstractBatchAcceptTask.java:56)2022-08-08 18:33:57,563 INFO [com.star.sms.business.accept2.BatchAcceptService$2] pool-91-thread-2 start|size=1
2022-08-08 18:33:57,600 INFO [com.star.sms.business.accept2.AcceptSheetContext] Current Thread: pool-91-thread-2 ######accept getsequence total time : 3 #####at com.star.sms.dao.utils.SmsJdbcTemplate.update(SmsJdbcTemplate.java:599)at com.star.sms.dao.resource.support.AbstractUpdateModel.doUpdate(AbstractUpdateModel.java:115)at com.star.sms.dao.resource.support.AbstractUpdateModel.insert(AbstractUpdateModel.java:77)at com.star.sms.dao.resource.AbstractResourceDaoJdbc.insert(AbstractResourceDaoJdbc.java:149)at com.star.sms.dao.resource.logicres.jdbc.CertResourceDaoImp.addCertResource(CertResourceDaoImp.java

从日志上看, 发现很多线程都卡在了数据库update 操作上 ,所以怀疑是数据库出现了死锁,执行下面的SQL查询统计,确认是否库中存在死锁

with vw_lock AS (SELECT * FROM v$lock)
select
a.sid,
'is blocking',
(select 'sid:'||s.sid||' object:'||do.object_name||' rowid:'||dbms_rowid.rowid_create ( 1, ROW_WAIT_OBJ#, ROW_WAIT_FILE#, ROW_WAIT_BLOCK#, ROW_WAIT_ROW# )||' sql_id:'||s.sql_idfrom v$session s, dba_objects dowhere s.sid=b.sidand s.ROW_WAIT_OBJ# = do.OBJECT_ID
) blockee,
b.sid,b.id1,b.id2
from vw_lock a, vw_lock b
where a.block = 1
and b.request > 0
and a.id1 = b.id1
and a.id2 = b.id2;
select * from v$session_wait t where t.WAIT_CLASS#<>6;

 查询结果:

SID  SEQ#  EVENT  P1TEXT	P1	P1RAW	P2TEXT	P2	P2RAW	P3TEXT
381	465	enq: TX - row lock contention	name|mode	1415053316	54580004	usn<<16 | slot	851989	000D0015	sequence
410	466	enq: TX - row lock contention	name|mode	1415053316	54580004	usn<<16 | slot	851989	000D0015	sequence
411	468	enq: TX - row lock contention	name|mode	1415053316	54580004	usn<<16 | slot	851989	000D0015	sequence
431	475	enq: TX - row lock contention	name|mode	1415053316	54580004	usn<<16 | slot	851989	000D0015	sequence

从查询结果发现,库中存在大量的行锁    enq: TX - row lock contention。 enq 是一种保护共享资源的锁定机制,一个排队机制

为了进一步确认那些个SQL死锁,通过行锁记录的SID 查询SQL详情,SQL如下

select se.SID, se.sql_id,se.SERIAL#,event,program,machine,q.SQL_TEXT,q.SQL_FULLTEXT,q.LAST_ACTIVE_TIMEfrom v$session se, v$sql qwhere wait_class# <> 6and se.SQL_ID = q.SQL_IDand sid  in (371,378,379,386,391)

查询结果

SQL_ID  EVENT  PROGRAM  MACHINE  SQL_TEXT  SQL_FULLTEXT
9vg758n0nm8vt  enq: TX - row lock contention  JDBC Thin Client  star10001874  INSERT INTO LOGICRESOURCEEN...  <CLOB>
9p3mtvy6ztgxq  SQL*Net message to client  PlSqlDev.exe  BJ\STAR10001874  select se.sql_id,event, .... 	     <CLOB>
9vg758n0nm8vt	enq: TX - row lock contention	JDBC Thin Client	star10001874	INSERT INTO LOGICRESOURCEEN...	<CLOB>
9vg758n0nm8vt	enq: TX - row lock contention	JDBC Thin Client	star10001874	INSERT INTO LOGICRESOURCEEN...	<CLOB>
9vg758n0nm8vt	enq: TX - row lock contention	JDBC Thin Client	star10001874	INSERT INTO LOGICRESOURCEEN...	<CLOB>

从查询结果看到,几个会话都有 TX锁,并且都是执行INTO LOGICRESOURCEEN.。然后查看线程栈日志中 SmsJdbcTemplate#update内容, 发现确实也是在执行LOGICRESOURCEEN表添加操作。 

TX 锁问题找到了, 那么为什么会产生TX锁呢?因为不了解TX锁所以查询了官方的文档。 我们用的是10g 版本的ORACEL, 下面的信息也是10g相关

2. Oracle 官方资料中TX相关描述

从查询结果看, 行锁发生在IINSERT NTO LOGICRESOURCEEN... 插入语句上  ,查询Oracle 官方资料中enq:TX - row lock contention. 相关信息


10.3.7.2.4 TX enqueue
These are acquired exclusive when a transaction initiates its first change and held until the transaction does a COMMIT or ROLLBACK.

10.3.7.2.4 TX排队

当事务启动其第一次更改时,这些数据将以独占方式获取,并一直保持到事务执行提交或回滚。

1. Waits for TX in mode 6: occurs when a session is waiting for a row level lock that is already held by another session. This occurs when one user is updating or deleting a row, which another session wishes to update or delete. This type of TX enqueue wait corresponds to the wait event enq: TX - row lock contention.

The solution is to have the first session already holding the lock perform a COMMIT or ROLLBACK.

大概意思:模式6TX等待:发证在当会话正在等待另一个会话已持有的行级锁时。即当一个用户正在更新或删除另一个会话希望更新或删除的行时,会发生这种情况。这种类型的TX排队等待对应于等待事件enq:TX - row lock contention.

解决方案:已经持有锁的第一个会话执行提交或回滚

2. Waits for TX in mode 4 can occur if the session is waiting for an ITL (interested transaction list) slot in a block. This happens when the session wants to lock a row in the block but one or more other sessions have rows locked in the same block, and there is no free ITL slot in the block. Usually, Oracle dynamically adds another ITL slot. This may not be possible if there is insufficient free space in the block to add an ITL. If so, the session waits for a slot with a TX enqueue in mode 4. This type of TX enqueue wait corresponds to the wait event enq: TX - allocate ITL entry.

The solution is to increase the number of ITLs available, either by changing the INITRANS or MAXTRANS for the table (either by using an ALTER statement, or by re-creating the table with the higher values).

大概意思:如果会话正在等待块中的ITL:当会话想要锁定块中的行,但一个或多个其他会话在同一块中锁定了行,并且块中没有空闲的ITL插槽时,会发生这种情况。通常,Oracle会动态添加另一个ITL插槽。如果区块中没有足够的可用空间来添加日志。 如果没有足够空间, 会话将在模式4中等待具有TX排队的插槽。这种类型的TX排队等待对应于“等待事件enq:TX-allocateITL entry”

解决方案:通过更改表的INITRANS或MAXTRANS(通过使用ALTER语句或通过使用更高的值重新创建表)来增加可用的ITL数量

备注: 之前也遇到过这个问题ITL事务槽不足引发了enq:TX-allocateITL entry等待事件, 有兴趣可进入传送门 ( 传送门:Oracle死锁问题: enq: TX - allocate ITL entry )

3. Waits for TX in mode 4 can also occur if a session is waiting due to potential duplicates in UNIQUE index. If two sessions try to insert the same key value the second session has to wait to see if an ORA-0001 should be raised or not. This type of TX enqueue wait corresponds to the wait event enq: TX - row lock contention.

The solution is to have the first session already holding the lock perform a COMMIT or ROLLBACK.

大概意思:如果会话由于唯一索引中的潜在重复而正在等待,如果两个会话试图插入相同的键值,则第二个会话必须等待,以查看是否应引发ORA-0001。这种类型的TX排队等待对应于“等待事件enq:TX - row lock contention.”

解决方案:已经持有锁的第一个会话执行提交或回滚

4. Waits for TX in mode 4 is also possible if the session is waiting due to shared bitmap index fragment. Bitmap indexes index key values and a range of ROWIDs. Each 'entry' in a bitmap index can cover many rows in the actual table. If two sessions want to update rows covered by the same bitmap index fragment, then the second session waits for the first transaction to either COMMIT or ROLLBACK by waiting for the TX lock in mode 4. This type of TX enqueue wait corresponds to the wait event enq: TX - row lock contention.

如模式4TX等待:会话由于共享位图索引片段而等待。位图索引索引键值和一系列行ID。位图索引中的每个“entry”可以覆盖实际表中的许多行。如果两个会话希望更新同一位图索引片段所覆盖的行,则第二个会话通过等待模式4中的TX锁来等待第一个事务提交或回滚。这种类型的TX排队等待对应于“等待事件enq:TX - row lock contention.

5. Waits for TX in mode 4 also occur when a transaction inserting a row in an index has to wait for the end of an index block split being done by another transaction. This type of TX enqueue wait corresponds to the wait event enq: TX - index contention.

当在索引中插入行的事务必须等待另一个事务完成的索引块拆分结束时,会发生TX锁等待。这种类型的TX排队等待对应于“等待事件 enq: TX - index contention.”


从上述内容分析可以可知, 通过COMMIT or ROLLBACK可以解锁, 参考SQL


--KILL 锁住的session
--例如:alter system kill session 'sid,serial#';alter system kill session '371,52558';
alter system kill session '378,10931';
alter system kill session '379,34850';
alter system kill session '386,35260';

3. 为什么INSERT 产生enq:TX - row lock contention.

从官网看,引起  enq:TX - row lock contention.等待事件的最大可能是LOGICRESOURCEEN中存在唯一约束。  查看表结构,数据表LOGICRESOURCEEN存在唯一约束RADIUSUNIQUE

alter table LOGICRESOURCEENadd constraint UQ_LGCRES_RADUSU unique (RADIUSUNIQUE)

 创建唯一约束的时候会同时创建唯一索引

select * from user_indexes where  table_name='LOGICRESOURCEEN';

查询结果:

INDEX_NAME	UNIQUENESS	TABLE_NAME	INDEX_TYPE	TABLE_TYPE
UQ_LGCRES_RADUSU	UNIQUE	LOGICRESOURCEEN	NORMAL	TABLE
PK_LOGICRESOURCEEN	UNIQUE	LOGICRESOURCEEN	NORMAL	TABLE
IDX$LOGRES_RADIUSCODESTR	NONUNIQUE	LOGICRESOURCEEN	NORMAL	TABLE
IDX$LOGRES_IPSTR	NONUNIQUE	LOGICRESOURCEEN	NORMAL	TABLE

4. 模拟自测



1. 两个事务分别向表LOGICRESOURCEEN做INSERT 操作,两次操作radiusunique完全相同
第一个事务执行后不COMMIT
第二个事务执行INSERT 后,卡死,无法执行COMMIT操作
此时查询数据库,库中存在两条执行记录的 enq: TX - row lock contention锁

2. 两个事务分别向表LOGICRESOURCEEN做INSERT 操作,两次操作radiusunique不同时
第一个事务执行后不COMMIT
第二个事务执行INSERT 后可以COMMIT操作


问题原因


        当确认是因为LOGICRESOURCEEN表中的RADIUSUNIQUE字段的值出现了相同值引发了死锁。所以排查 RADIUSUNIQUE 字段产生的方式。  通过这个突破口很容易就发现RADIUSUNIQUE字段生成规则存在缺陷, 特定条件下会产生相同的编码。最终,通过解决程序问题避免RADIUSUNIQUE相同解决enq:TX - row lock contention.等额问题

        整个排查过程学到了很多,另外也发现工作中要保持一颗平常心,勿急、勿燥、勿上火。

        希望对看到这篇文章的朋友有所帮助

      

上一篇:Oracle 如何使用循环控制关键字exit、goto、continue



http://chatgpt.dhexx.cn/article/4QtHJHuN.shtml

相关文章

oracle dump enq hw,enq:HW–contention 故障处理

enq: HW - contention 说明&#xff1a; 硬件队列用于序列化段的高水位线以外的空间分配。 可以用手动分配范围即可解决问题。 V$SESSION_WAIT,P2 / V$LOCK.ID1 is the tablespace number. V$SESSION_WAIT.P3 / V$LOCK.ID2 is the relative data block address (dba) of segmen…

oracle enq ta,Oracle 的 enq: TT - contention 等待事件

Oracle 的 enq: TT - contention 等待事件 在遇到 TT 锁等待时,你可能会被Oracle的文档所困扰。即便是在Oracle Database 12c的文档中,关于TT锁的描述也是:Temporary table enqueue。 这其实已经不准确了,从数据库中可以得到更详细和准确的描述,V$LOCK_TYPE中有着准确记录…

oracle enq ta,enq: TA – contention 等待事件

enq: TA – contention 等待事件 This enqueue is used when undo tablespace operations are being performed. Some examples of such operations are: When dropping an undo tablespace we acquire the enqueue in exclsuive mode to stop other sessions using the undo t…

关于AQS中的enq方法的理解

自己太笨了&#xff0c;总感觉有点绕&#xff0c;就整理下吧~ private Node enq(final Node node) {//自旋锁for (;;) {//tail默认就是nullNode t tail;if (t null) { // Must initialize//因为tail默认是null&#xff0c;所以首次一定会进来//compareAndSetHead在下面//也就…

队列等待之enq: TX - row lock contention

【性能优化】队列等待之enq: TX - row lock contention 问题背景&#xff1a; 客户反映某条sql DELETE SHAREINNERDOC WHERE SOURCEID:B1<br/>这个执行时间太长 问题解决 1> 查看awr报告&#xff1a; 有队列等待之enq: TX - row lock contention&#xff0c;对应的sq…

等待事件 enq:TX - row lock contention分析与解决

6月30日&#xff0c;数据库发生了大量锁表。大概持续1小时&#xff0c;并且越锁越多。后来通过业务人员停掉程序&#xff0c;并kill掉会话后解决。 几天后再EM上查看CPU占用&#xff1a; CPU发生了明显等待。 主要是由于enq:TX - row lock contention等待事件造成。 等待事…

java -- 随机获取字母或者数字

java只有涉及到随机的&#xff0c;最经常用到的方法就是Math.random()&#xff0c;这个方法会返回一个大于0小于1的随机数( 能取0不能取1 )&#xff0c;如果我们要随机0-9&#xff0c;就可以用&#xff08;Math.random()*10&#xff09;来表示&#xff0c;随机0-99也类似如此操…

JavaScript生成随机字母数字字符串

如何使用javascript生成随机字母数字字符串&#xff1f;下面本篇文章就来给大家介绍一下使用JavaScript生成随机字母数字字符串的方法&#xff0c;希望对大家有所帮助。 方法一&#xff1a;Math.random()方法和Math.floor()方法 ● 创建一个函数&#xff0c;该函数有两个参数…

Python - 怎么将一个数字拆分成多个随机数字

前情提要 使用numpy.random.choice()的时候&#xff0c;通过参数p&#xff08;一个列表&#xff09;来指定所给选择元素的选择概率。但参数p&#xff08;选择概率&#xff09;要保证和为1&#xff0c;这时我又想随机生成选择概率&#xff0c;所以现在的问题就是怎么将1拆分成多…

python随机生成一个数字_如何实现python随机生成数字?

今天小编就生成随机数,整理了多个方式,方便大家在项目时,根据自己的需求,直接拿来套用即可,以下内容相当详细,具体来看看吧~ 说明:python中生成随机数主要用到random模块,方法主要包括:randint、uniform、random、sample、choice等几种常用方法; 环境:Mac OS 10.1…

python随机生成三位数字_python3 随机生成数字

原博文 2019-11-25 10:07 − random模块 random.randint(1,10)--随机生成0-10之间的随机整数 random.uniform(1,10)--随机生成0-10之间的实数 random.randrange(9,100,10)--从9-100之间随机选取一个实数,差为10,也就是说从9,19,29,39,49... 0 3530 相关推荐 2019-12-0…

C#生成含数字字母的随机字符串

C#生成含数字字母的随机字符串 要求生成的字符串是随机的&#xff0c;也就是字母和数字都需要随机&#xff0c;既可能只包含数字&#xff0c;也可能只包含字母&#xff0c;也可能两者都有。 实现方式如下: 首先定义一个包含所有字母和数字的字符串和一个空串&#xff0c;随后…

css 随机 数,纯CSS实现随机效果

最近在Codepen上看到了Adir写的随机翻牌和找蛋蛋(可以想象是砸金蛋)效果&#xff0c;让我再次刷新了对CSS的认知。看到这两个效果之后我才知道&#xff0c;在CSS中除了可以实现 来自其他语言的随机性 众所周知&#xff0c;CSS是一种声明式的标记语言。在很多同学的认知中&#…

舒尔特表-5*5表格1-25个数字随机生成且不重复

大家好&#xff1a;最近在玩快速记忆&#xff0c;看到舒尔特表&#xff0c;整理出一版来。v1.0版本。 舒尔特表&#xff1a;5*5表格 1-25个数字&#xff0c;随机生成且不重复。 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http:/…

计算机随机数字excel,excel怎么生成随机数字 excel随机数字区间怎么设定

excel是我们日常生活中处理表格数据必备的工具&#xff0c;当我们知道了一定范围内的数值&#xff0c;并且不用精准的数值时&#xff0c;我们完全可以设置excel随机生成数字即可&#xff0c;怎么设置?很简单&#xff0c;下面小编为大家带来excel生成随机数字的详细教程&#x…

随机生成4个数字php,PHP随机生成4位数字的方法

//方法1 $code .mt_rand(1000,9999).; echo $code; echo ; //方法2 $code .mt_rand(1000,9999).; echo $code; echo ; //方法3 $code ; $code..mt_rand(0,9).; $code..mt_rand(0,9).; $code..mt_rand(0,9).; $code..mt_rand(0,9).; echo $code; echo ; //方法4 $code ; $r…

java生成1到10的随机数_用java生成一个1到10十个数字随机排列的数组

效果如图&#xff1a; 代码如下public class ArrayListToAry { public static void main(String[] args) { // 数组 int[] ary new int[10]; // 集合 ,临时集合temp存放1~10个数字 ArrayList temp new ArrayList(); //list集合存放需要的数字 ArrayList list new ArrayList(…

你知道如何生成随机数吗?(超详细附图)

目录 &#x1f609;前言 &#x1f378;如何用C语言实现随机数 &#x1f379;随机数原理 &#x1f379;rand函数&#xff08;生成随机数&#xff09; &#x1f379;srand&#xff08;避免每次运行程序产生的随机数都相同&#xff09; &#x1f379;时间戳 &#x1f964;t…

如何批量生成个位随机数字

众所周知&#xff0c;条码软件可以批量打印条码二维码以及各种各样的产品标签&#xff0c;功能比较齐全&#xff0c;在输入数据时有各种类型&#xff0c;比如手动输入、计数器生成、数据库字段、日期时间、序列生成、流水号等等。今天小编给大家介绍如何随机生成个位数字。 打开…

使用cmd查看端口号

打开cmd命令窗口&#xff1b;输入 netstat -nao|findstr "端口号" &#xff1b;在本地地址中查看端口号&#xff0c;并记住该进程的PID&#xff1a;在运行中输入taskmgr打开任务管理器&#xff0c;在名称一处右击&#xff0c;选中PID&#xff1b;查看第三步的PID所对…