Oracle定位行锁的数据行

背景

今天上午在查询行锁的事后发现v$lock的id1和id2,阻塞的和被阻塞的会话一样,这能说明什么?

既然是被阻塞了,那争用的应该是同一块数据,但是一个事务已经修改了,没提交数据块上还有前镜像的指针,另一个事务想要修改(这里应该修改不了那为什么id1和id2一样呢),应该是构造一致性读去读取这个地址吧?

这里计一个todo,先来看看根据行锁定位到具体是哪一个表的行数据产生了行锁。

首先id1和id2其实是和 v$trasaction 的字段相对应的

id1=xidusn+xidslot(回滚段号+回滚槽号)

id2=xidsqn(回滚槽号的覆盖次数)

后面说计算,这三个记录在数据块的 ITL,相对应的还有被修改数据的前镜像uba(回滚段地址)

uba在v$trasaction也有记录,

uba=回滚块地址(文件号+块号)+ 回滚序列号 + 回滚记录号

总结一下就是当前事务的三个xid、四个uba 和上面一一对应记录在v$trasaction

select xidusn,xidslot,xidsqn,ubafil,ubablk,ubasqn,ubarec from v$transaction;

思路:事务记录在块的ITL,尝试根据v$trasaction的回滚段号和块号找到发生行锁的块地址。

环境

Oracle11g

sql 复制代码
SYS@orcl> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
CORE    11.2.0.4.0      Production
TNS for Linux: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production

模拟行锁

这里用本地的一个测试表demo01数据如下:

构造行锁,修改id=2的行数据id:2 name:test2 sex:男

接下来假装不知道是这里发生的阻塞,去这行数据

会话一:

sql 复制代码
SYS@orcl> update demo01 set sex='男' where id=2;

1 row updated.

SYS@orcl> 

会话二

我们知道的情况下就好办了,直接找到数据块,dump下来

sql 复制代码
select rowid,
       dbms_rowid.rowid_relative_fno(rowid) rel_fno,
       dbms_rowid.rowid_block_number(rowid) blockno
  from demo01
 where id = 2;

实验

查找行锁信息

sql 复制代码
select sn.username,
       sn.LAST_CALL_ET,
       sn.COMMAND,
       sn.STATUS,
       m.sid,
       sn.serial#,
       sn.sql_id,
       m.type,
       decode(m.lmode,
              0,
              'none',
              1,
              'null',
              2,
              'rowshare',
              3,
              'rowexcl.',
              4,
              'share',
              5,
              'srowexcl.',
              6,
              'exclusive',
              lmode,
              ltrim(to_char(lmode, '990'))) lmode,
       decode(m.request,
              0,
              'none',
              1,
              'null',
              2,
              'rowshare',
              3,
              'rowexcl.',
              4,
              'share',
              5,
              'srowexcl.',
              6,
              'exclusive',
              request,
              ltrim(to_char(m.request, '990'))) request,
       m.id1,
       m.id2
  from v$session sn, v$lock m
 where (sn.sid = m.sid and m.request != 0) --存在锁请求,即被阻塞
    or (sn.sid = m.sid --不存在锁请求,但是锁定的对象被其他会话请求锁定
       and m.request = 0 and lmode != 4 and
       (id1, id2) in (select s.id1, s.id2
                         from v$lock s
                        where request != 0
                          and s.id1 = m.id1
                          and s.id2 = m.id2))
 order by id1, id2, m.request;

可以看到sid=427的会话在2024-12-05 10:50:42登录一直处于INACTIVE, LAST_CALL_ET:9772s,发生阻塞的数据在demo01

根据阻塞会话的 sid 就能找到v$trasaction ,有xid信息,undo 信息ubafile ubablk

sql 复制代码
select
    s.sid
  , s.serial#
  , s.username
  , t.addr taddr
  , s.saddr ses_addr
  , t.used_ublk
  , t.used_urec
--  , t.start_time
  , to_char(t.flag, 'XXXXXXXX') "0xFLAG"
  , t.status||CASE WHEN BITAND(t.flag,128) = 128 THEN ' ROLLING BACK' END status
  , t.start_date
  , XIDUSN
  , XIDSLOT
  , XIDSQN
  , t.xid
  , t.prv_xid
  , t.ptx_xid
from
    v$session s
  , v$transaction t
where
    s.saddr = t.ses_addr and sid=427;

id2=2070=xidsqn

id1=262163转成十六进制4 0013

高位4=xidusn,低位0013(十六进制)=xidslot=19(十进制)

又可以得到uba

select * from v$transaction where xidusn=4 and xidslot=19 and xidsqn=2070;

uba=回滚块地址(文件号+块号)+ 回滚序列号 + 回滚记录号

3号文件 4364块

dump undo块
sql 复制代码
SYS@orcl> alter system dump datafile 3 block 4364;
System altered.
SYS@orcl> exec get_trace_name
/u01/app/oracle/diag/rdbms/orcl/orcl/trace\orcl_ora_5296.trc
PL/SQL procedure successfully completed.
dump undo 段头

根据上面的xid与v$rollname的usn关联得到段头

sql 复制代码
SYS@orcl> select name from v$rollname where usn=4;

NAME
------------------------------
_SYSSMU4_1254879796$

dump undo段头

sql 复制代码
SYS@orcl> ALTER SYSTEM DUMP UNDO BLOCK '_SYSSMU4_1254879796$' XID 4 19 2070;

System altered.

SYS@orcl> exec get_trace_name

/u01/app/oracle/diag/rdbms/orcl/orcl/trace\orcl_ora_1484.trc

PL/SQL procedure successfully completed.

--bdba 表示block address hdba 代表sgment header address

--当中 bdba 表示file 4,block 94,449 , hdba 表示file 4。block 94,448

block address:

sgment header address:

找到块地址之后就可以dump数据块了

dump 数据块 <<找到行锁的数据
sql 复制代码
SYS@orcl> alter system dump datafile 1 block 94449;

System altered.

SYS@orcl> 
SYS@orcl> exec get_trace_name

/u01/app/oracle/diag/rdbms/orcl/orcl/trace\orcl_ora_6708.trc

PL/SQL procedure successfully completed.

SYS@orcl> 

得到dump的块,想得到被锁住的行数据 一是在数据区找到真正的数据(还没学会bbed)二是在尾区找,我们来找一下:

dump的一段内容:

block_row_dump:

tab 0, row 0, @0x1c57 ----第一个表第一行的位置 ,定义了该表在行索引中的起始插槽号

tl: 16 fb: --H-FL-- lb: 0x0 cc: 3 ----行头,tl 表示行的总长度(total length)这里是 8 个节。

--fb 表示行的标志字节(flag byte),用来标识行的状态。D表示被删除,这个之前做过实验Oracle delete删除数据是否为逻辑删除、新插入数据占用的数据块位置实验 - 墨天轮

--cc:3 -表示有列数,这个表有三个字段。

col 0: [ 2] c1 02 --第一行的第一个字段长度和值

--表示第 0 列的内容是一个长度为 2 的值,十六进制为 c1 02

col 1: [ 5] 74 65 73 74 31 --同理第一行的第二个字段长度和值

--表示第 1 列的内容是一个长度为 5 的值,十六进制为 74 65 73 74 31

col 2: [ 3] e5 a5 b3

tab 0, row 1, @0x1c67

tl: 16 fb: --H-FL--lb: 0x2 cc: 3 <<< ----lb: 0x1 说明事物在该数据行上的锁还没清除,并且该锁指向 02 号事物槽如下图。

col 0: [ 2] c1 03

col 1: [ 5] 74 65 73 74 32

col 2: [ 3] e7 94 b7

通过UTL_RAW转化一下,就可以看到被锁住的表的行数据了

有意思,非常有意思,实验室参考下面的文章做的,刚吸收一点点,我在去学习一下。

参考:

oracle回滚机制深入研究 - ldxsuanfa - 博客园

相关推荐
dazhong20121 小时前
PLSQL 客户端连接 Oracle 数据库配置
数据库·oracle
了一li3 小时前
Qt中的QProcess与Boost.Interprocess:实现多进程编程
服务器·数据库·qt
码农君莫笑3 小时前
信管通低代码信息管理系统应用平台
linux·数据库·windows·低代码·c#·.net·visual studio
别致的影分身4 小时前
使用C语言连接MySQL
数据库·mysql
京东零售技术5 小时前
“慢”增长时代的企业数据体系建设:超越数据中台
数据库
sdaxue.com6 小时前
帝国CMS:如何去掉帝国CMS登录界面的认证码登录
数据库·github·网站·帝国cms·认证码
o(╥﹏╥)6 小时前
linux(ubuntu )卡死怎么强制重启
linux·数据库·ubuntu·系统安全
阿里嘎多学长7 小时前
docker怎么部署高斯数据库
运维·数据库·docker·容器
Yuan_o_7 小时前
Linux 基本使用和程序部署
java·linux·运维·服务器·数据库·后端
Sunyanhui17 小时前
牛客网 SQL36查找后排序
数据库·sql·mysql