2012-06-06 98 views
2

我有一些C#代碼,它在事務內部使用「ON COMMIT DELETE ROWS」選項創建了幾個Oracle臨時表。在事務中截斷Oracle臨時表,截斷* ALL *臨時表

在事務內部,我會插入一堆行到各種臨時表中。在某些情況下,我需要截斷一個特定的臨時表,以便我可以重新開始使用該表,但保留其他臨時表。

我發現Oracle在執行截斷時必須執行隱式COMMIT,因爲不僅特定的臨時表被截斷,而且我的臨時表的所有都被截斷。

好吧,我已經在其他地方看過,截斷命令被認爲是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(); 
    } 
} 

回答

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; 
+0

發現我的測試場景出錯了。我在我的測試程序的第二次運行中基於結果,此時臨時表已經在數據庫中,因此沒有發出CREATE TABLE,因此也沒有COMMIT,也沒有自動截斷其他臨時表。 –