最近写了个多线程任务处理组件用来处理大批量的业务数据, 从业务监控数据中发现少量业务数据修改时一直处于等待状态,很明显是出现类似 for update 锁表,锁行的情况。
这种问题是系统设计(复杂的业务逻辑)导致的,暂时只能从数据库层次解决,因为修改系统设计比较复杂,也没有那么多时间。
解决思路:
1.查出锁住该表的会话id,serial#
SELECT object_name,machine,s.sid,s.serial# FROM gv$locked_object l,dba_objects o,gv$session s WHERE l.object_id=o.object_id AND l.session_id=s.sid;
SELECT o.object_name,s.sid, s.serial# FROM v$lock l, dba_objects o, v$session s WHERE l.id1= o.object_id AND l.sid = s.sid AND o.object_name='SJ_AFFAIR';
2.kill掉该会话
alter system kill session 'sid, serial#';
3.代码临时优化:修改“初始表”数据时进行锁表尝试:for update nowait ,这个成本貌似有点高, 由于这种场景通常是数据异常场景,所以有监控就够了,因为7万票才偶尔出现一次,暂时不处理代码。
理论扫盲:
二、V$LOCK和V$LOCKED_OBJECT
查询锁表都会用到V$LOCK和V$LOCKED_OBJECT,但这两者不是相同的。我们先看看它们各自的主要字段:
1.v$lock
sid: 会话SID,通常与v$session关联。
type: 锁类型,TM表示表锁或DML锁,TX表示行锁或事务锁,UL表示用户锁。我们主要关注TX和TM两种型的锁其它均为系统锁,会很快自动释放,不用关注。行锁不会单独存,行级锁之前需要先加表级共享锁。
lmode: 会话保持的锁的模式。
0=None;1=Null;2=Row-S (SS,行级共享锁,其他对象只能查询这些数据行);3=Row-X (SX,行级排它锁,在提交前不允许做DML操作);4=Share(共享锁);5=S/Row-X (SSX,共享行级排它锁);6=Exclusive(排它锁)
ID1,ID2: ID1,ID2的取值含义根据type的取值而有所不同,对于TM 锁ID1表示被锁定表的object_id 可以和dba_objects视图关联取得具体表信息,ID2 值为0;对于TX 锁ID1以十进制数值表示该事务所占用的回滚段号和事务槽slot number号,其组形式: 0xRRRRSSSS,RRRR=RBS/UNDO NUMBER,SSSS=SLOT NUMBER,ID2 以十进制数值表示环绕wrap的次数,即事务槽被重用的次数
2.V$LOCKED_OBJECT
session_id: 会话id。通常与v$session关联。
object_id: 被锁对象标识。通常与dba_objects关联。
oracle_username: 登录oracle用户名。
os_user_name: 电脑用户名如:Administrator
locked_mode: 会话保持的锁的模式。
三、两者的区别
1.V$LOCKED_OBJECT只能报发生等待的表级锁,不能报发生等待的行级锁。
注:这句话是网上别人说的,暂时未验证,需慎重考虑。但是从我遇到的问题来看,似乎是正确的。只是我的问题已经无法重现,也就失去了验证它的机会。
2.v$locked_object包含的是当前DB中被锁住的OBJECT,而v$lock不仅包含用户的,还包括系统被锁住的object,即: V$LOCK>v$locked_object
如果觉得《大批量数据修改时发现有一行数据被锁住了 一直处于等待状态的问题解决》对你有帮助,请点赞、收藏,并留下你的观点哦!