【问题标题】:Oracle: Getting a deadlock every now and then when truncating tables in our testsOracle:在我们的测试中截断表时不时出现死锁
【发布时间】:2017-06-21 09:29:33
【问题描述】:

我们有大约 500 个测试,每晚在 Oracle 数据库上运行。

在每次测试之前,我们使用以下代码截断所有表:

    public override void EmptyTables()
    {
        const string alterConstraints = "begin for i in (select c.* from user_constraints c, user_tables u where c.table_name = u.table_name and c.constraint_type = 'R') LOOP EXECUTE IMMEDIATE 'alter table ' || i.table_name || ' {0} constraint ' || i.constraint_name; end loop; end;";

        List<string> commandList = new List<string>();
        commandList.Add( string.Format( alterConstraints, "disable" ) );
        commandList.AddRange( GetTableNames().Select( tn => string.Format( "truncate table {0}", tn ) ) );
        commandList.Add( string.Format( alterConstraints, "enable" ) );

        ExecuteNonQuery( commandList );
    }

    public virtual void ExecuteNonQuery( IList<string> statements )
    {
        DbTransaction dbTransaction = DbConnection.BeginTransaction();
        foreach( string statement in statements )
        {
            DbCommand dbComand = CreateDbCommand( statement, dbTransaction );
            dbComand.CommandTimeout = 60 * 30;

            try
            {
                dbComand.ExecuteNonQuery();
            }
            catch( Exception exception )
            {
                HandleExecuteNonQueryException( exception, dbTransaction, statement );
            }
            finally
            {
                dbComand.Dispose();
            }
        }

        dbTransaction.Commit();
    }

几乎每天晚上,这些测试中的一些(约 5 个,随机)在 ExecuteNonQuery 失败,出现 ORA-00060 或 ORA-04020 死锁(语句:alter table SOMETABLE 禁用约束 FK_SOMEFK => 表和 FK 和禁用/启用是随机的以及)。

我知道找出问题可能非常棘手,但可能有人有想法:)

谢谢!

【问题讨论】:

  • 最明显的是其他人正在使用该表。在更改表格之前尝试ALTER SESSION SET DDL_LOCK_TIMEOUT = 60,这样您的等待时间最长可达 60 秒。
  • 谢谢,我会尽力告诉你的。
  • 不,没有帮助。

标签: oracle deadlock


【解决方案1】:

我将从收集有关测试失败的统计数据开始。

在每次调用EmptyTables方法前检查并记录查询结果:

select obj.owner,
       obj.object_name,
       obj.object_type,
       s.sid,
       s.serial#,
       s.status,
       s.osuser,
       s.machine
  from v$locked_object lo,
       v$session s,
       dba_objects obj
 where s.sid = lo.session_id
   and lo.object_id = obj.object_id;

首先查找被先前测试运行中打开的会话锁定的对象。

考虑到故障的“随机”性质和情况的可重复性,我看到了两种可疑的可能性:

  1. 如果您使用 多个会话 运行测试,由于某种原因,之前测试的会话没有足够的时间来释放资源。您第一次可以终止查询找到的会话,直到您了解它们没有正确关闭的原因。

  2. 如果所有测试都重用同一个会话,那么(如 cmets 中所述)肯定会有其他人在测试运行时使用该模式。但我认为情况并非如此,因为您为测试运行制作了良好的隔离架构:我希望您在开始测试之前创建它并在测试之后将其删除。

为了快速失败,您可以在 DDL 操作之前锁定每个表:

LOCK TABLE table_name IN EXCLUSIVE MODE NOWAIT;

【讨论】:

  • 谢谢,我会尽力告诉你的。目前没有对表 v$session 的权限。
猜你喜欢
  • 2012-05-07
  • 1970-01-01
  • 2012-06-10
  • 2011-06-16
  • 1970-01-01
  • 1970-01-01
  • 2022-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多