转载自love wife & love life —Roger 的Oracle技术博客

本文链接地址: ORA-01591: lock held by in-doubt distributed transaction

  1. 昨天某客户遇到一个问题是关于两阶段分布式事务的,大概是内容是
  2. 一个定时job执行失败,然后报如下错误:
  1. Sun Oct 9 02:38:12 2011
  2. Errors in file /ora/app/admin/oraapp/bdump/oraapp1_j000_643178.trc:
  3. ORA-12012: error on auto execute of job 84
  4. ORA-01591: lock held by in-doubt distributed transaction 19.3.5343485
  5. ORA-06512: at "SODB_ADMIN.PKG_SODB_MAINTAIN", line 1064
  6. ORA-06512: at line 1
  7. Sun Oct 9 02:59:45 2011
  8. Thread 1 advanced to log sequence 63561
  1. 这里我们首先需要关注是 ORA-01591 错误,
  1. Error: ORA 1591
  2. Text: lock held by in-doubt distributed transaction <num >
  3. -------------------------------------------------------------------------------
  4. Cause: An attempt was made to access a resource locked by a dead two-phase
  5. commit transaction that is in prepared state.
  6. Action: Match the transaction number in the message with the GLOBAL_TRAN_ID
  7. column of the DBA_2PC_PENDING table to determine the database link and
  8. the state of the transaction.
  9. Attempt to repair network connections to the coordinator and commit
  10. point, if necessary.
  11. If timely repair is not possible, contact the database administrator
  12. at the commit point, if known, to resolve the pending transaction.
  1. 如上是mos关于该错误的一个描述,当然,引起该错误的原因可能有很多很多。
  2. 关于分布式事务,其实可以这样理解,就是一个完整的事务,其中包含的多个操作分布在
  3. 两个以上的数据库中,只有这些操作都全部完成了,该事务才算完成,不然该事务都将失败。
  4.  
  5. 换句话说,如果该事务失败了,其中涉及到操作表A,那么当其他session访问到表A时将出现
  6. ORA-01591错误。
  7.  
  8. 至于具体说为什么分布式事务会失败,那么就要具体分析了,可能是程序本身的问题或者网络
  9. 问题等等。
  10.  
  11. 我们回到我客户的问题上来,既然是分布事务,那么我们就查询dba_2pc_pending视图:
  12. 查询结果如下;
  1. LOCAL_TRAN_ID STATE FAIL_TIME OS_USER DB_USER
  2. ---------------------- ---------------- ------------ ---------- ----------
  3. 56.29.120915 prepared 09-SEP-11 t3smisbw
  4. 19.3.5343485 prepared 01-OCT-11 t3smisbw
  5. 12.15.3794557 prepared 03-OCT-11 t3smisbw
  1. 从上可以看到,目前该库有3个失败的分布事务,其中 19.3.5343485 是我们需要处理的。
  2.  
  3. 关于字段LOCAL_TRAN_ID的解释,大家可以去查看dba_2pc_pending的说明,这里只简单的
  4. 描述一下;
  5.  
  6. LOCAL_TRAN_ID 格式为:xidusn + xidslot + xidsqn
  7.  
  8. 下面继续查询当前系统回滚段中是否还有如上几个失败的分布式事务信息:
  1. SQL> SELECT KTUXEUSN,
  2. 2 KTUXESLT,
  3. 3 KTUXESQN, /* Transaction ID */
  4. 4 KTUXESTA STATUS,
  5. 5 KTUXECFL Flags
  6. 6 FROM x$ktuxe
  7. 7 WHERE ktuxesta != 'INACTIVE'
  8. 8 AND ktuxeusn IN(56,19,12) ORDER BY 1;
  9.  
  10. KTUXEUSN KTUXESLT KTUXESQN STATUS FLAGS
  11. ---------- ---------- ---------- ---------------- ------------------------
  12. 12 15 3794557 PREPARED SCO|COL|REV|EXTDTX
  13. 19 3 5343485 PREPARED SCO|COL|REV|DEAD|EXTDTX
  14. 56 29 120915 PREPARED SCO|COL|REV|EXTDTX
  1. 我们可以发现,仍然存在,这处理就简单了,处理之前我还需要说明一下的是:
  2.  
  3. 根据分布事务的状态(state)不同,我们需要采取不同的方法进行处理,稍后进行一个
  4. 简单的总结,这里我继续描述如何处理该问题。
  5.  
  6. 通过如下两个小步骤进行处理:
  7.  
  8. rollback force '19.3.5343485';
  9. execute dbms_transaction.purge_lost_db_entry('19.3.5343485');
  10.  
  11. 然后再次执行该job,正常。
  12.  
  13. 当然这仅仅是一个处理的办法,我们最终的目的是想知道为什么该分布事务会执行失败呢?
  14.  
  15. 先来查询该job的基本信息:
  1. SQL> SELECT job,SCHEMA_USER,LAST_DATE,NEXT_DATE,BROKEN,FAILURES,INSTANCE
  2. 2 FROM dba_jobs;
  3.  
  4. JOB SCHEMA_USER LAST_DATE NEXT_DATE B FAILURES INSTANCE
  5. --- ------------ ------------ ------------ - ---------- ----------
  6. ............
  7. 83 SODB_ADMIN 10-OCT-11 11-OCT-11 N 0 0
  8. 84 SODB_ADMIN 07-OCT-11 11-OCT-11 N 12 0
  9. 85 SODB_ADMIN 10-OCT-11 11-OCT-11 N 0 0
  10. ............
  11.  
  12. 13 ROWS selected.
  13.  
  14. JOB SCHEMA_USER LAST_DATE NEXT_DATE B FAILURES INTERVAL INSTANCE
  15. --- ----------- --------- ---------- - -------- ------------------------------------------- --------
  16. ..........
  17. 84 SODB_ADMIN 07-OCT-11 11-OCT-11 N 12 trunc(sysdate)+1+2/24+25/24/60 0
  18. 85 SODB_ADMIN 10-OCT-11 11-OCT-11 N 0 trunc(sysdate)+1+2/24+50/24/60 0
  19. ..........
  20.  
  21. 13 ROWS selected.
  1. job (job number84) 已经执行失败12次了,INTERVAL是该job的执行间隔。对于dba_jobs中的 FAILURES字段,
  2. 该字段最大值为16,每次执行失败后该值递增,但是一旦执行成功后将被清0.
  3.  
  4. 从报错信息来看,该job执行失败问题出在PKG_SODB_MAINTAIN1064行,通过dbms_metadata获取定义后,发现
  5. 如下信息:
  6.  
  7. 该过程执行到如下步骤时失败:
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  1. PROCEDURE refine_msg (p_date IN DATE)
  2. IS
  3. v_id NUMBER;
  4. BEGIN
  5. proc_expired_msg_log (p_date - pkg_sodb.get_expired_msg_days);
  6. proc_expired_msg_tbm (p_date - pkg_sodb.get_expired_tbm_days);
  7. EXCEPTION
  8. WHEN OTHERS
  9. THEN
  10. ROLLBACK;
  11. pkg_sodb.add_event_log ('SODB',
  12. 'PKG_SODB_MAINTAIN',
  13. 'Refine_Msg',
  14. 'DB_ERROR',
  15. 3,
  16. SYSDATE,
  17. 'êy?Y?a2ù×÷òì3£',
  18. NULL,
  19. v_id
  20. );
  21. COMMIT;
  22. RAISE;
  23. END refine_msg;
  1. 其中: Proc_Expired_Msg_Log Proc_Expired_Msg_Tbm 为存储过程;
  2. Get_Expired_Msg_Days Get_Expired_Tbm_Days 为过程PKG_SODB中的2个函数;
  3.  
  4. 这样来看似乎问题就出在这里,我怀疑可能是业务逻辑什么的可能有问题,比如
  5. Proc_Expired_Msg_Log(p_date - PKG_SODB.Get_Expired_Msg_Days) 有可能计算出来
  6. 是负数吗?或者说执行到该步时,后面的rolllback操作时,其他前面的事务是否还存在关联?
  7.  
  8. 不是开发出身,分析起来有些麻烦,主要是这几个包里面包含了太多的存储过程和函数,
  9. 看起来就头晕,最好建议客户找开发商看看这几个包。
  10.  
  11. 补充:关于分布式事务处理的简单总结
  1. ++++++ 常规处理步骤 ++++++
  2.  
  3. 1. Identify the id OF the TRANSACTION:
  4.  
  5. COLUMN global_tran_id format a25
  6. COLUMN DATABASE format a22
  7. COLUMN global_name format a22
  8. SELECT * FROM global_name;
  9. SELECT LOCAL_TRAN_ID, GLOBAL_TRAN_ID,to_char(FAIL_TIME,'dd-mon-yyyy HH24:MI:SS'),STATE, MIXED FROM DBA_2PC_PENDING;
  10. SELECT LOCAL_TRAN_ID, IN_OUT,INTERFACE, DATABASE FROM DBA_2PC_NEIGHBORS;
  11.  
  12. 2. Purge the TRANSACTION:
  13.  
  14. EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('<transaction_id>');
  15. COMMIT;
  16.  
  17. 3. Confirm that the TRANSACTION has been purged:
  18.  
  19. SELECT LOCAL_TRAN_ID, GLOBAL_TRAN_ID,to_char(FAIL_TIME,'dd-mon-yyyy HH24:MI:SS'),STATE, MIXED FROM DBA_2PC_PENDING;
  20. SELECT LOCAL_TRAN_ID, IN_OUT,INTERFACE, DATABASE FROM DBA_2PC_NEIGHBORS;
  21.  
  22. 其中有如下五种state
  23.  
  24. collecting
  25. -- execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('1.10.255');
  26. prepared
  27. -- rollback force tran_id/commit force tran_id;
  28. EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('1.10.255');
  29. committed
  30. -- execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('1.10.255');
  31. forced commit
  32. -- execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('1.10.255');
  33. forced ROLLBACK
  34. -- execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('1.10.255');
  35.  
  36.  
  37. ++++++ 如果遇到ORA-30019错误,可以采取如下方式:++++++
  38.  
  39. ALTER SESSION SET "_smu_debug_mode" = 4;
  40. EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('1.10.255');
  41.  
  42. ====== 情况1 dba_2pc_pending表中还有事务记录,但是实际已经不存在该事务了
  43.  
  44. SELECT LOCAL_TRAN_ID,
  45. GLOBAL_TRAN_ID,
  46. to_char(FAIL_TIME, 'dd-mon-yyyy HH24:MI:SS'),
  47. STATE,
  48. MIXED
  49. FROM DBA_2PC_PENDING;
  50.  
  51. LOCAL_TRAN_ID 1.92.66874 prepared
  52.  
  53. 1 为回滚段号
  54.  
  55. SELECT KTUXEUSN,
  56. KTUXESLT,
  57. KTUXESQN, /* Transaction ID */
  58. KTUXESTA STATUS,
  59. KTUXECFL Flags
  60. FROM x$ktuxe
  61. WHERE ktuxesta != 'INACTIVE'
  62. AND ktuxeusn = 1
  63.  
  64. 返回为0
  65.  
  66. 如果当状态为prepared,且事务表中也不存在相关信息,那么我们只能手工进行清理:
  67.  
  68. ++++++ 使用如下方式进行手工处理:++++++
  69.  
  70. SET TRANSACTION USE ROLLBACK segment SYSTEM;
  71. DELETE FROM sys.pending_trans$ WHERE local_tran_id = '1.92.66874';
  72. DELETE FROM sys.pending_sessions$ WHERE local_tran_id = '1.92.66874';
  73. DELETE FROM sys.pending_sub_sessions$ WHERE local_tran_id = '1.92.66874';
  74. commit;
  75.  
  76. ====== 情况2 dba_2pc_pending表中无法查到分布式事务信息,但是实际上却是存在该分布式事务的
  77.  
  78. SELECT LOCAL_TRAN_ID,
  79. GLOBAL_TRAN_ID,
  80. to_char(FAIL_TIME, 'dd-mon-yyyy HH24:MI:SS'),
  81. STATE,
  82. MIXED
  83. FROM DBA_2PC_PENDING;
  84.  
  85. 查询无记录
  86.  
  87. SELECT local_tran_id, state
  88. FROM dba_2pc_pending
  89. WHERE local_tran_id = ' 1.92.66874 '; -- 为空
  90.  
  91. SELECT KTUXEUSN,
  92. KTUXESLT,
  93. KTUXESQN, /* Transaction ID */
  94. KTUXESTA STATUS,
  95. KTUXECFL Flags
  96. FROM x$ktuxe
  97. WHERE ktuxesta != 'INACTIVE'
  98. AND ktuxeusn = 1;
  99.  
  100. 查询有记录
  101.  
  102. ====== 此种情况下,我们无法手工进行ROLLBACKcommit ======
  103.  
  104. ++++++ 我们用如下的方式手工清理:++++++
  105.  
  106. ALTER system disable distributed recovery ;
  107.  
  108. INSERT INTO pending_trans $
  109. (LOCAL_TRAN_ID,
  110. GLOBAL_TRAN_FMT,
  111. GLOBAL_ORACLE_ID,
  112. STATE,
  113. STATUS,
  114. SESSION_VECTOR,
  115. RECO_VECTOR,
  116. TYPE #,
  117. FAIL_TIME,
  118. RECO_TIME)
  119. VALUES
  120. (' 1.92.66874 ',
  121. 306206,
  122. ' XXXXXXX.12345.1.2.3 ',
  123. ' prepared ',
  124. ' P ',
  125. hextoraw(' 00000001 '),
  126. hextoraw(' 00000000 '),
  127. 0,
  128. sysdate,
  129. sysdate);
  130.  
  131. INSERT INTO pending_sessions $
  132. VALUES
  133. (' 1.92.66874 ',
  134. 1,
  135. hextoraw(' 05004F003A1500000104 '),
  136. ' C ',
  137. 0,
  138. 30258592,
  139. '',
  140. 146);
  141.  
  142. commit ;
  143.  
  144. commit force ' 1.92.66874 ' ;
  145.  
  146. ++++++ 此时如果commit force还是出现报错,需要继续执行:++++++
  147.  
  148. 1. DELETE FROM pending_trans $ WHERE local_tran_id = '1.92.66874' ;
  149. 2. DELETE FROM pending_sessions $ WHERE local_tran_id = '1.92.66874' ;
  150. 3. commit ;
  151. 4. ALTER system enable distributed recovery ;
  152. 5. ALTER SESSION SET " _smu_debug_mode " = 4 ;
  153. 6. EXEC dbms_transaction.purge_lost_db_entry ( '1.92.66874' )
  154.  
  155. ====== 另外我们还可以通过如下SQL来捕获到导致分布式事务失败的SQL:======
  156.  
  157. ++++++ 获取local_tran_id ++++++
  158.  
  159. SELECT a.sql_text, s.osuser, s.username
  160. FROM v$transaction t, v$session s, v$sqlarea a
  161. WHERE s.taddr = t.addr
  162. AND a.address = s.prev_sql_addr
  163. AND t.xidusn = 1
  164. AND t.xidslot = 25
  165. AND t.xidsqn = 589367;
  166.  
  167. 如果 v$session v$sqlarea 已经无法查到,那么我们还可以关联一些 dba_hist_* 试图进行查询。

ORA-01591 锁定已被有问题的分配事务处理--解决方法(转)的更多相关文章

  1. AppStore下载失败使用已购页面再试一次解决方法

    AppStore载失败 使用已购页面再试一次解决方法 工具/原料 Mac OS 方法/步骤 1.大家可以先试试更改系统 DNS 的方法,由于苹果的 App Store 应用商店在国外,所以 DNS 如 ...

  2. mac os 错误提示:下载失败 使用已购页面再试一次 解决方法

    最近由于买了macbook,开始用mac os系统,发现一个奇怪的现象,在app store里下载应用,老是提示:下载失败 使用已购页面再试一次 原来一直不知道怎么解决这个问题,今天研究了下,发现解决 ...

  3. SAP无输入历史记录(已在本地数据开启历史记录)解决方法

    SAP客户端已开启本地数据的历史记录,但是仍然没有录入记录,重装SAP无法解决问题,没有最近输入记录操作极为不方便,经研究表现出的问题特征如下:1.同一用户在另一台电脑使用SAP就有历史记录,到了本电 ...

  4. VS提示无法连接到已配置的开发web服务器的解决方法

    VS2013每次启动项目调试好好的,今天出现了提示“提示无法连接到已配置的开发web服务器“,使用环境是本地IISExpress,操作系统为windows10,之前也出现过就是重启电脑又好了,这次是刚 ...

  5. ubuntu中出现:程序 'java' 已包含在下列软件包中的解决方法

    已经安装sun java 在终端中输入java,出现以下提示: 程序 'java' 已包含在下列软件包中: * default-jre * gcj-4.8-jre-headless * gcj-4.9 ...

  6. 显示器驱动程序 NVIDIA Windows Kernel Mode Driver Version 已停止响应 并且己成功恢复 解决方法

    原文:http://news.160.com/?p=1890 在玩游戏中 经常 出现显示器驱动程序 NVIDIA Windows Kernel Mode Driver Version 已停止响应 并且 ...

  7. SqlServer2008 无法修改表,超时时间已到 在操作完成之前超时解决方法

    在 SQL Server Management Studio 里, 通过菜单“工具-选项”打开选项对话框. 在左侧寻找“设计器-表设计器和数据库设计器”, 然后在右侧勾选“为表设计器更新重写连接字符串 ...

  8. 本地连接出现"已启用检测该状态的服务"解决方法、方案

    1.运行 输出dcomcnfg 2.组件服务-计算机-我的电脑-DCOM配置-netprofm 3.右键属性-安全-启动和激活权限-自定义 4.编辑-添加-输入对象名称来选择-输入“LOCAL SER ...

  9. 【转】"超时时间已到。在操作完成之前超时时间已过或服务器未响应"的解决方法

    方法有以下三种: 1.原因应该在数据访问有问题,可以把连接时间设置长些,在数据库连接字符串,加上Connect Timeout=18000,单位毫秒 2,在web.config中加上以下语句: < ...

随机推荐

  1. 原始套接字-自定义IP首部和TCP首部

    /* ===================================================================================== * * Filenam ...

  2. js 正则之 检测素数

    相信很多人应该看过这篇文章,我第一次看到的时候是11年的样子,那时候学vbs的时候看过这个问题.原文<检查素数的正则表达式>,在文章里已经解释了他是怎么判断的,我就不啰嗦了.我们来说说 j ...

  3. JavaScript继承详解(四)

    在本章中,我们将分析Douglas Crockford关于JavaScript继承的一个实现 - Classical Inheritance in JavaScript. Crockford是Java ...

  4. Ascending Rating(单调队列)

    题目描述 Before the start of contest, there are n ICPC contestants waiting in a long queue. They are lab ...

  5. 使用 scm-manager 搭建 git/svn 代码管理仓库(二)

    主要介绍scm的配置. 1.配置为在Windows服务中启动scm-manager的启动方式有多种,可以在DOS(即命令行CMD模式)中启动,也可以在Windows服务中启动. 下面我们采用Windo ...

  6. 【mongoDB】 分享系列

    mongoDB 作为一个非关系性数据库(功能很像关系型数据库) MongoDB 之一 MongoDB是什么 MongoDB 之二 增-删-改-查 MongoDB 之三 数据类型 MongoDB 之四 ...

  7. expect学习笔记及实例详解【转】

    1. expect是基于tcl演变而来的,所以很多语法和tcl类似,基本的语法如下所示:1.1 首行加上/usr/bin/expect1.2 spawn: 后面加上需要执行的shell命令,比如说sp ...

  8. python的map/reduce区别

    直接上列子 map: 把f(x)作用在list的每一个元素并把结果生成一个新的list” # coding=utf-8def f(x): return x * x r = map(f, [1, 2, ...

  9. python3.3中print换行

    python  3.3版本中的print默认有个换行的操作 如: for i in range(5): print(i) 结果为: 01234 如果不想换行,需要用到print函数的end参数,pri ...

  10. sublime text 3 使用简介

    2014年1月22日 09:47:50 2用了一段时间感觉不错,就是自带的高亮显示匹配标签或者代码块儿时有点儿不清楚,所以一直是sublime 开PHP,notepad++开html 现在想只用一个编 ...