【问题标题】:Oracle: How to find out if there is a transaction pending?Oracle:如何查明是否有待处理的事务?
【发布时间】:2010-11-20 22:40:47
【问题描述】:

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

【问题讨论】:

标签: oracle transactions


【解决方案1】:
SELECT * FROM V$TRANSACTION
WHERE STATUS='ACTIVE';

见: http://forums.oracle.com/forums/thread.jspa?threadID=691061

【讨论】:

    【解决方案2】:

    您可以检查您的会话是否在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 将启动一个即使您没有更改任何数据,也可以进行交易。此方法不保证您有未提交的数据。 ...您知道有什么方法可以改进此查询以过滤掉此类交易吗?这真的让我很困惑。
    • @CarloSirna 是的,在某些情况下,即使您不更改数据,Oracle 也会启动事务。连接到远程数据库就是一个例子(参见例如this thread on Asktom)。一个简单的SELECT ... FOR UPDATE 也将在不修改数据的情况下启动事务。我的回答中描述的方法告诉您是否有待处理的事务,而不是您是否有未提交的数据。两者不等价(修改数据就足够了,但不是启动事务所必需的)。
    【解决方案3】:

    【讨论】:

    • :-) 不同的描述......“未提交的工作”与“待处理的交易”
    【解决方案4】:

    这是我通常使用的查询,

    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;
    

    【讨论】:

    • 效果很好,我还需要在使用 ALTER SYSTEM KILL SESSION 'sid,serial#'; 之后终止非活动事务;
    【解决方案5】:

    使用下面的查询找出待处理的交易。

    如果它返回一个值,则表示有一个待处理的事务。

    这里是查询:

    select dbms_transaction.step_id from dual;

    参考资料:
    http://www.acehints.com/2011/07/how-to-check-pending-transaction-in.html http://www.acehints.com/p/site-map.html

    【讨论】:

    • 执行 SET TRANSACTION 然后运行您的查询。
    • @PeterNosko:您建议的解决方案效果很好,但与 DBA 建议的简单 select dbms_transaction.step_id from dual; 相比,它相当复杂。 step_id 返回:如果没有事务,则返回 NULL,如果事务存在但为空,则返回 0,如果有任何未决的更改,则返回非 null、非零值。恕我直言,这比您的版本简单得多,并告诉我们更多有关连接状态的信息。您是否发现 step_id 存在任何使其不可靠的问题?
    【解决方案6】:

    可以修改 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;
    

    【讨论】:

      【解决方案7】:

      最简单、最可靠的解决方案是尝试启动事务,看看是否成功。如果某些代码已经开始了一个事务但还没有发出任何 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;
      /
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-20
        • 2010-12-11
        • 2015-02-15
        • 1970-01-01
        • 2016-07-17
        • 2012-11-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多