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 - 博客园

相关推荐
C嘎嘎嵌入式开发8 分钟前
什么是僵尸进程
服务器·数据库·c++
Yeats_Liao2 小时前
Navicat 导出表结构后运行查询失败ERROR 1064 (42000): You have an error in your SQL syntax;
数据库·sql
明月看潮生3 小时前
青少年编程与数学 02-007 PostgreSQL数据库应用 15课题、备份与还原
数据库·青少年编程·postgresql·编程与数学
明月看潮生3 小时前
青少年编程与数学 02-007 PostgreSQL数据库应用 14课题、触发器的编写
数据库·青少年编程·postgresql·编程与数学
加酶洗衣粉8 小时前
MongoDB部署模式
数据库·mongodb
Suyuoa8 小时前
mongoDB常见指令
数据库·mongodb
添砖,加瓦8 小时前
MongoDB详细讲解
数据库·mongodb
Zda天天爱打卡8 小时前
【趣学SQL】第二章:高级查询技巧 2.2 子查询的高级用法——SQL世界的“俄罗斯套娃“艺术
数据库·sql
我的运维人生8 小时前
MongoDB深度解析与实践案例
数据库·mongodb·运维开发·技术共享
步、步、为营8 小时前
解锁.NET配置魔法:打造强大的配置体系结构
数据库·oracle·.net