使用"嵌套" oracle中的事务

时间:2014-07-01 09:29:44

标签: c# oracle plsql transactions

我在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新手,无法找到与此类似的解决方案。请有人告诉我我做错了什么。

2 个答案:

答案 0 :(得分:6)

Oracle不支持嵌套事务。如果事务提交,则提交。这就是为什么您通常不想在存储过程中提交(或回滚)事务的原因,这使得如果您的事务语义不同,很难在其他地方重用该过程。

但是,您可以在过程开始时声明一个保存点,并在出现错误时回滚到该保存点。如果然后删除提交,则事务仅由应用程序代码控制,而不是由数据库代码

控制
begin
  savepoint beginning_of_proc;

  insert/update/delete...

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

在这种情况下,我的偏见是在代码中没有保存点,没有回滚,除非你正在做一些有用的事情,否则不要捕获异常。只需执行DML,就可以抛出任何异常,并在应用程序中处理它们。

答案 1 :(得分: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;
/