Oracle:如何查找是否有挂起的事务?

43

我想找到一种方法来确定当前会话中是否存在未提交的INSERT、UPDATE或DELETE语句。一种方法是使用当前sid检查v$lock,但这需要读取v$lock,如果DBA不想授予访问权限,则会出现问题。除了跟踪应用程序发出的所有数据库命令之外,还有其他方法吗?


我假设你没有访问任何V$视图的权限。 - Gren
可能是如何判断Oracle事务中是否有未提交的工作?的重复问题。 - Matthew Strawbridge
我们可以在未提交的事务中获取sql_text。 - Bade Dba
7个回答

49

您可以检查会话是否在V$TRANSACTION中有一行(显然,这需要对此视图具有读取权限):

SQL> SELECT COUNT(*)
       FROM v$transaction t, v$session s, v$mystat m
      WHERE t.ses_addr = s.saddr
        AND s.sid = m.sid
        AND ROWNUM = 1;

  COUNT(*)
----------
         0

SQL> insert into a values (1);

1 row inserted

SQL> SELECT COUNT(*)
       FROM v$transaction t, v$session s, v$mystat m
      WHERE t.ses_addr = s.saddr
        AND s.sid = m.sid
        AND ROWNUM = 1;

  COUNT(*)
----------
         1

SQL> commit;

Commit complete

SQL> SELECT COUNT(*)
       FROM v$transaction t, v$session s, v$mystat m
      WHERE t.ses_addr = s.saddr
        AND s.sid = m.sid
        AND ROWNUM = 1;

  COUNT(*)
----------
         0

有些情况下,这种方法不起作用,会返回错误的结果:例如,如果你只是使用数据库链接从远程数据库中选择数据(select * from remotetable@databaselink),即使你没有修改任何数据,Oracle也会启动一个事务。这种方法不能保证你有未提交的数据。 ...你知道如何改进这个查询以过滤掉这种类型的事务吗?这真的让我感到困惑。 - Carlo Sirna
1
@CarloSirna 是的,有些情况下即使您不更改数据,Oracle也会启动事务。连接到远程数据库就是一个例子(例如,请参见Asktom上的此线程)。一个简单的SELECT ... FOR UPDATE也会启动一个事务而不修改数据。我回答中描述的方法告诉您是否有待处理的事务,而不是未提交的数据。这两者并不等价(修改数据足以但不必要启动事务)。 - Vincent Malgrat

35

这是我通常使用的查询语句:

select s.sid
      ,s.serial#
      ,s.username
      ,s.machine
      ,s.status
      ,s.lockwait
      ,t.used_ublk
      ,t.used_urec
      ,t.start_time
from v$transaction t
inner join v$session s on t.addr = s.taddr;

3
运行良好,同时我需要使用“ALTER SYSTEM KILL SESSION 'sid,serial#'”来终止不活动的事务。 - Diizzy

11

2
ORA-00942: 表或视图不存在 00942. 00000 - "表或视图不存在" *原因: *操作: 错误位于行:1 列:15 - jsanmarb

10

执行 SET TRANSACTION,然后运行您的查询。 - Peter Nosko
@PeterNosko:你提出的解决方案很好,但与DBA建议的简单的select dbms_transaction.step_id from dual;相比,它相当复杂。step_id返回:如果没有事务,则为NULL;如果存在事务但为空,则为0;如果有任何待处理更改,则为非空、非零值。在我看来,这比你的版本简单得多,并告诉我们更多关于连接状态的信息。你是否发现step_id存在不可靠的问题? - quetzalcoatl

4

1
不同的描述... "未提交的工作" vs "待处理的事务" - cagcowboy

2

最简单可靠的解决方案是尝试启动事务并查看是否成功。如果某些代码已经启动了事务但尚未发出任何DML,则V$TRANSACTION视图将不显示任何内容。

在下面的示例中,我处理异常以引发用户定义的应用程序错误。要推迟到现有的异常处理程序,只需执行 SET TRANSACTION 然后立即 COMMIT 以撤消它。

DECLARE
    transaction_in_progress EXCEPTION;
    PRAGMA EXCEPTION_INIT(transaction_in_progress, -1453);
BEGIN
    SET TRANSACTION NAME 'CHECK_FOR_TRANSACTION_ALREADY_SET';
    COMMIT; -- end transaction
EXCEPTION
    WHEN transaction_in_progress THEN
        RAISE_APPLICATION_ERROR(-20000,'Transaction is already in progress');
END;
/

2

Matthew Watson可以被修改以用于RAC

select t.inst_id 
       ,s.sid
      ,s.serial#
      ,s.username
      ,s.machine
      ,s.status
      ,s.lockwait
      ,t.used_ublk
      ,t.used_urec
      ,t.start_time
from gv$transaction t
inner join gv$session s on t.addr = s.taddr;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接