2014-07-01 61 views
1

我在Oracle中遇到了事務問題。我有一些程序是這樣的:在oracle中使用「嵌套」事務

create or replace procedure myschema.DataSave(v_value IN NUMBER) 
as 
begin 

SET TRANSACTION ISOLATION LEVEL READ COMMITTED; 

begin 
insert/update/delete... 
exception when OTHERS then goto error; 
end; 

COMMIT; 
return; 

<<error>> 
ROLLBACK; 
return; 
end; 
/

我打電話這種形式從C#項目這個程序:

... 
string conn_str = "..."; 
OracleConnection con = new OracleConnection(conn_str); 
con.Open(); 
OracleCommand cmd = new OracleCommand("", con); 

try 
{ 
    cmd.Transaction = cmd.Connection.BeginTransaction(); 

    for (int i = 0; i < 10; i++) 
    { 
     // this condition simulates incorrect situations 
     if (i == 5) 
     { 
      throw new Exception("Something is wrong."); 
     } 

     cmd.CommandType = CommandType.StoredProcedure; 
     cmd.CommandText = "myschema.DataSave"; 
     cmd.Parameters.Clear(); 
     cmd.Parameters.Add("v_value", OracleDbType.Int32, i, ParameterDirection.Input); 
    } 

    cmd.Transaction.Commit(); 
} 
catch (Exception ex) 
{ 
    cmd.Transaction.Rollback(); 
} 
finally 
{ 
    con.Close(); 
    con.Dispose(); 
} 
... 

所以我想在數據庫中使用一個「內部」或「嵌套」的交易層和應用層上的另一個「外部」事務。但是,當拋出應用程序中的異常時,回滾不起作用(先前保存的數據 - 1,2,3,4 - 保留在數據庫中)。但爲什麼?我沒有使用MSSQL和存儲過程,以這種形式來面對這個問題:

create procedure myschema.DataSave 
@id as int 
as 
begin 

    begin transaction 

    insert/update/delete... 
    if @@error > 0 goto error 

    commit transaction 
    return 

    error: 
    rollback transaction 
    return 
end 
go 

進出口新的Oracle和無法找到解決silimilar了這一點。請有人告訴我我做錯了什麼。

回答

5

Oracle不支持嵌套事務。如果事務提交,它將提交。這就是爲什麼你通常不想在存儲過程中提交(或回滾)一個事務的原因,如果你的事務語義不同,就很難在別處重用這個過程。

但是,您可以在過程開始時聲明保存點,並在出現錯誤時回滾到該保存點。如果隨後刪除了提交,那麼交易是完全由應用程序代碼控制,不是由數據庫代碼

begin 
    savepoint beginning_of_proc; 

    insert/update/delete... 

exception 
    when OTHERS then 
    rollback to beginning_of_proc; 
    raise; 
end; 

在這種情況下,雖然,我的偏見是不是有一個保存點在代碼中,不有一個回滾,而不是捕捉異常,除非你正在做一些有用的事情。只要做DML,讓任何異常拋出,並在你的應用程序中處理它們。

1

例外僅限於他們在提出的程序組。

create or replace procedure myschema.DataSave(v_value IN NUMBER) 
as 

ex_dml_error EXCEPTION; 
begin 


begin 
insert/update/delete... 
exception 
    when OTHERS then ex_dml_error; 
end; 

COMMIT; 

EXCEPTION 
    WHEN ex_dml_error THEN 
    ROLLBACK; 
end; 
/