oracle自主事务造成的死锁

小明 2025-05-04 19:13:18 6

���主事务->single resource的死锁,可以通过查看trace看是否是一个资源会话造成的死锁,如果是,那就是自主事务的原因。

多数死锁都是两个资源争用:

自主事务的是一个TX-资源在争用导致的,基本上一个资源争用导致的死锁,就是自主事务引起的:

一般来说有自主事务的process会有多个session,自己一个,自主事务单独创建一个,然后去争夺资源,导致死锁。

实验过程:

创建一个自主事务的存储过程p2

create or replace procedure p2 is 
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
  update t2 set object_name=object_name||'1' where owner='SCOTT';
  commit;
END;
/
SQL> update t2 set object_name=object_name||'1' where owner='XDB';
1168 rows updated.
SQL> select distinct object_name from t2 where owner='XDB' and rownum exec p2;
PL/SQL procedure successfully completed.

按道理来说,在p2已经commit了,接下来的rollback是不生效的才对

SQL> rollback;
Rollback complete.

但是确实生效了,说明自主事务是自己单独一个会话。

SQL> select distinct object_name from t2 where owner='XDB' and rownum update t2 set object_name=object_name||'1' where owner='SCOTT';
6 rows updated.
SQL> exec p2;
BEGIN p2; END;
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
ORA-06512: at "TEST.P2", line 4
ORA-06512: at line 1

查看trace文件:

Deadlock graph:
                       ---------Blocker(s)--------  ---------Waiter(s)---------
Resource Name          process session holds waits  process session holds waits
TX-0005001d-00000369        19     191     X             19     191           X

这就很色,持有者和等待者都是一样的。但我们去看SO就会发现不同之处,一个process底下有俩session,两个SO的owner不一样,同样的TX-资源被两个SO会话持有,因此导致了资源征用

持有者mode: X的SO的owner是 0xf38ac1b0

SO: 0xef3ee108, type: 56, owner: 0xf38ac1b0, flag: INIT/-/-/0x00 if: 0x3 c: 0x3
       proc=0xf351da98, name=transaction, file=ktccts.h LINE:410, pg=0
      (trans) flg = 0x00000e03, flg2 = 0x00014000, flg3 = 0x00000000, prx = (nil), ros = 2147483647, crtses=0xf38ac1b0
      flg  = 0x00000e03: ALC TRN VUS VID CHG
      flg2 = 0x00014000: IMU IMP
      flg3 = 0x00000000:
      bsn = 0x26ba bndsn = 0x26bd spn = 0x26c8
      efd = 5 rfd = 0 DID:
      file:kta.c lineno:1670
      parent xid: 0x0000.000.00000000
      env [0xef3ee520]: (scn: 0x0000.000e4b24  xid: 0x0005.01d.00000369  uba: 0x00c0103e.00b6.06  statement num=0  parent xid: 0x0000.000.00000000  st-scn: 0x0000.000e4b24  hi-scn: 0x0000.00000000  ma-scn: 0x0000.00000000  flg: 0x00000000)
      cev: (spc = 7518  arsp = 0xef4639e0  ubkds (ubk:tsn: 2 rdba: 0x00c0103e flag:0x8 hdl:(nil) addr:(nil))  useg tsn: 2 rdba: 0x00c000c0
            hwm uba: 0x00c0103e.00b6.06  col uba: 0x00000000.0000.00
            num bl: 1 bk list: 0xef33b7f0)
            cr opc: 0x0 spc: 7518 uba: 0x00c0103e.00b6.06
      Begin scn:0x0000.000e4ae4 uba:0x00c0103e.00b6.01 ts:1658744536[07/25/2022 18:22:16]
      Undo blks: 1 recs: 6
      ccbstg: 0x00000000
      (enqueue) TX-0005001D-00000369    DID: 0001-0013-00000013
      lv: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  res_flag: 0x6
      mode: X, lock_flag: 0x0, lock: 0xef3ee180, res: 0xf3e01160
      own: 0xf38ac1b0, sess: 0xf38ac1b0, proc: 0xf351da98, prv: 0xf3e01170

请求者req: X的SO的owner是 0xf38ff2e8

SO: 0xf3902fc0, type: 3, owner: 0xf38ff2e8, flag: INIT/-/-/0x00 if: 0x3 c: 0x3
       proc=0xf351da98, name=call, file=ksu.h LINE:12725, pg=0
      (call) sess: cur f38ac1b0, rec 0, usr f38ac1b0; flg:0 fl2:1; depth:1
      svpt(xcb:(nil) sptn:0x26cb uba: 0x00000000.0000.00)
      ksudlc FALSE at location: 0
        ----------------------------------------
        SO: 0xf3d41cb8, type: 8, owner: 0xf3902fc0, flag: INIT/-/-/0x00 if: 0x1 c: 0x1
         proc=0xf351da98, name=enqueue, file=ksq1.h LINE:380, pg=0
        (enqueue) TX-0005001D-00000369  DID: 0001-0013-00000013
        lv: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  res_flag: 0x6
        req: X, lock_flag: 0x10, lock: 0xf3d41d10, res: 0xf3e01160
        own: 0xf38ac1b0, sess: 0xf38ac1b0, proc: 0xf351da98, prv: 0xf3e01180

只要把自主事务的那个存储过程中自主事务给注释了,就不会造成死锁了,因为他们这样就算是一个事务了。

The End
微信