【问题标题】:Truncating an Oracle Temp Table in a Transaction, Truncates *ALL* Temp Tables截断事务中的 Oracle 临时表,截断 *ALL* 临时表
【发布时间】:2012-06-10 21:12:32
【问题描述】:

我有一些 C# 代码在事务中使用“ON COMMIT DELETE ROWS”选项创建多个 Oracle 临时表。

在事务内部,我会将一堆行插入到各种临时表中。在某些情况下,我需要截断特定的临时表,以便我可以从该表重新开始,但不理会其他临时表。

我发现,当您执行截断时,Oracle 必须执行隐式 COMMIT,因为不仅特定的临时表被截断,而且我的所有临时表都被截断。

好的,我在其他地方读到 Truncate 命令被视为 DDL 命令,这就是为什么正在处理提交,这导致我的“ON COMMIT DELETE ROWS”临时表被清除。

如果这是真的,那么创建一个新的临时表的行为难道不是一个 DDL 命令,而且它还会触发清除所有其他临时表的同一个提交吗?如果是这样,我还没有看到这种行为。我在我的代码中创建了新的临时表,发现之前创建的临时表在新的临时表创建后仍然保持完整的行。

这里有一些演示问题的 C# 代码(这里不包括帮助例程):

private void RunTest()
{
  if (_oc == null)
    _oc = new OracleConnection("data source=myserver;user id=myid;password=mypassword");

  _oc.Open();
  _tran = _oc.BeginTransaction();

  string tt1 = "DMTEST1";
  AddTempTable(tt1, false);
  int TempTableRowCount0 = GetTempTableRowCount(tt1);

  AddRows(tt1, 5);
  int TempTableRowCount10 = GetTempTableRowCount(tt1);

  string tt2 = "DMTEST2";
  AddTempTable(tt2, false);
  int TempTableRowCount12 = GetTempTableRowCount(tt1); // This will have the same value as TempTableRowCount10
  AddRows(tt2, 6);
  int TempTableRowCount13 = GetTempTableRowCount(tt2); // This will have the same value as TempTableRowCount10

  string tt3 = "DMTEST3";
  AddTempTable(tt3, true); // The TRUE argument which does a TRUNCATE against the DMTEST3 table is the problem
  int TempTableRowCount14 = GetTempTableRowCount(tt1); // This will return 0, it should be = TempTableRowCount10
  int TempTableRowCount15 = GetTempTableRowCount(tt2); // This will return 0, it should be = TempTableRowCount13

  _tran.Commit();
  _tran = null;
  int TempTableRowCount20 = GetTempTableRowCount(tt1); // This should be 0 because the transaction was committed 
  int TempTableRowCount21 = GetTempTableRowCount(tt2); // and the temp tables are defined as "ON COMMIT DELETE ROWS"
}

private void AddTempTable(string TableName, bool Truncate)
{
  IDbCommand ocmd = new OracleCommand();
  ocmd.Connection = _oc;
  if (!TableExists(TableName))
  {
    ocmd.CommandText = string.Format("CREATE GLOBAL TEMPORARY TABLE {0} ({1}) ON COMMIT DELETE ROWS", TableName, "FIELD1 Float");
    int rc = ocmd.ExecuteNonQuery();
  }
  if (Truncate)
  {
    ocmd.CommandText = "TRUNCATE TABLE " + TableName;
    int rc = ocmd.ExecuteNonQuery();
  }
}

【问题讨论】:

    标签: c# oracle transactions temporary


    【解决方案1】:

    在 Oracle 中,您不会在运行时创建全局临时表。您在部署系统时创建一次。每个会话都会自动获得它自己的临时表“副本”。

    另外,如果您可以避免 TRUNCATE,我会推荐它 - 即,如果您可以依靠 ON COMMIT DELETE ROWS 导致数据在您提交时消失,那么这是最有效的方法。

    回答您的其他问题(“CREATE GLOBAL TEMPORARY 似乎没有提交”) - 我自己尝试过,在我看来 CREATE GLOBAL TEMPORARY 确实提交了。我的测试用例:

    create global temporary table test1 (n number) on commit delete rows;
    insert into test1 values (1);
    --Expected: 1
    select count(*) from test1;
    commit;
    --Expected: 0
    select count(*) from test1;
    insert into test1 values (2);
    --Expected: 1
    select count(*) from test1;
    create global temporary table test2 (n number) on commit delete rows;
    --Expected: 0
    select count(*) from test1;
    commit;
    --Expected: 0
    select count(*) from test1;
    

    【讨论】:

    • 发现我的测试场景有问题。我的结果基于我的测试程序的第二次运行,那时临时表已经在数据库中,所以没有发出 CREATE TABLE ,因此没有提交,也没有自动截断其他临时表。
    猜你喜欢
    • 1970-01-01
    • 2018-12-29
    • 1970-01-01
    • 1970-01-01
    • 2010-12-04
    • 2011-08-23
    • 1970-01-01
    • 2011-02-06
    • 2011-02-08
    相关资源
    最近更新 更多