我有一些C#代码在事务中创建了几个带有“ON COMMIT DELETE ROWS”选项的Oracle临时表。
在事务内部,我会将一堆行插入到各种临时表中。在某些情况下,我需要截断一个特定的临时表,以便我可以从该表开始新的,但保留其他临时表。
我发现Oracle在执行Truncate时必须执行隐式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();
}
}
答案 0 :(得分:5)
在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;