开发者

VB OracleTransaction Not Rolling back

I'm calling a third party stored procedure in Oracle from VB that is not rolling back.

Code first (I'm simplifying):

Connection string:

String sqlstr = "SERVER=x.x.x.x;Database=db;uid=sa;pwd=admin;Connect Timeout=60; Min Pool Size=5; Max Pool Size=100;";

The call (I've just forced a rollback immediately after the execute to test it):

Dim Oraclecon As New OracleConnection(_OracleConnection)
Dim sqlCon As New SqlConnection(_SQLConnection)
Dim oTrans As OracleTransaction = Nothing

 Oraclecon.Open()
 oTrans = Oraclecon.BeginTransaction()
 Dim myCMD As New OracleCommand()
 myCMD.Connection = Oraclecon
 myCMD.Transaction = oTrans
 myCMD.CommandText = "CREATE_USER"
 myCMD.CommandType = CommandType.StoredProcedure
 myCMD.Parameters.Add(New OracleParameter("username", OracleType.VarChar)).Value = UserName
 myCMD.Parameters.Add(New OracleParameter("passwd", OracleType.VarChar)).Value = Password
 myCMD.Parameters.Add(New OracleParameter("speed", OracleType.VarChar)).Value = Speed
 myCMD.Parameters.Add(New OracleParameter("monthly_quota", OracleType.VarChar)).Value = Quota
 myCMD.Parameters.Add(New OracleParameter("type", 开发者_JAVA技巧OracleType.VarChar)).Value = "H"
 Dim oparam As OracleParameter
 oparam = New OracleParameter("success_flag", OracleType.VarChar)
 oparam.Size = 1
 oparam.Direction = ParameterDirection.Output

 Dim oparam2 As OracleParameter
 oparam2 = New OracleParameter("err_msg", OracleType.VarChar)
 oparam2.Direction = ParameterDirection.Output
 oparam2.Size = 100

 myCMD.Parameters.Add(oparam)
 myCMD.Parameters.Add(oparam2)

 Dim RowId As OracleString

 myCMD.ExecuteOracleNonQuery(RowId)
 oTrans.Rollback()

I can't give the details of the stored procedure but it does a commit and rollback inside it.

Either way, it is doing an insert, and that immediate rollback does not rollback the insert.

Any ideas?


The Commit/Rollback logic in the PL/SQL (regardless of AUTONOMOUS TRANSACTION clause --> DO NOT USE THIS unless you are error logging: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:2212445691154)

So if you issue a COMMIT in your package your data is commited, PERIOD. Rollback the same way.

Create table for the following examples:

create  table SHOW_TRANSACTION (MISC varchar2(15)) ;
/

Looking at this example shows just that:

declare

   procedure DOTHEINSERT(DATAM in SHOW_TRANSACTION.MISC%type ,
                        doCommit IN boolean

   ) 
   as
   begin    
            insert into SHOW_TRANSACTION (MISC) 
            values (DATAM);

            if DOCOMMIT   then
               commit ;
            else
               ROLLBACK ;
            end if;
   end ;
begin
    DOTHEINSERT('commit1' , true);
    DOTHEINSERT('NOcommit1' , false);
    DOTHEINSERT('commit2' , true);
    DOTHEINSERT('NOcommit2' , false);
    DOTHEINSERT('commit3' , true);
    ROLLBACK;


end ;
/

select * from SHOW_TRANSACTION ;
/
MISC            
--------------- 
commit1         
commit2         
commit3   

Notice the final ROLLBACK does nothing? this is because the COMMIT/ROLLBACKS in the procedure are effecting the entire scope, look at this example:

truncate table SHOW_TRANSACTION; --start with clean slate

declare

   procedure DOTHEINSERT(DATAM in SHOW_TRANSACTION.MISC%type ,
                        doCommit IN boolean

   ) 
   as
   begin    
            insert into SHOW_TRANSACTION (MISC) 
            values (DATAM);

            if DOCOMMIT   then
               commit ;
            --else (HERE I AM GETTING RID OF THE PROCEDURES ROLLBACK, SO EVERYTHING IS BEING ROLLBACK'ED
            --   ROLLBACK ;

            end if;
   end ;
begin
    DOTHEINSERT('commit1' , true);
    DOTHEINSERT('NOcommit1' , false);
    DOTHEINSERT('commit2' , true);
    DOTHEINSERT('NOcommit2' , false);
    DOTHEINSERT('commit3' , true);
    ROLLBACK;


end ;
/

select * from SHOW_TRANSACTION ;
/

MISC            
--------------- 
commit1         
NOcommit1       
commit2         
NOCOMMIT2       
commit3     

Here the package ROLLBACK is removed, so when that COMMIT happens, the contents of all the INSERTS prior to that are inserted.

If you want the VB application to handle the transaction, you must remove the commit/rollback from the PL/SQL.

Also, it does not matter where the commit/rollback are, they are indicative to the ENTIRE SCOPE of all items in the transaction:

truncate table SHOW_TRANSACTION ; 

declare

   procedure DOTHEINSERT(DATAM in SHOW_TRANSACTION.MISC%type ,
                        doCommit IN boolean

   ) 
   as
          procedure DOTHETRANSACTION(doCommit IN boolean) as 
          begin
            if DOCOMMIT   then
               commit ;
            else -- (HERE I AM GETTING RID OF THE PROCEDURES ROLLBACK, SO EVERYTHING IS BEING ROLLBACK'ED
               ROLLBACK ;
            end if;             
          END DOTHETRANSACTION;
   begin    
            insert into SHOW_TRANSACTION (MISC) 
            values (DATAM);
            DOTHETRANSACTION(doCommit);
   end DOTHEINSERT;
begin
    DOTHEINSERT('commit1' , true);
    DOTHEINSERT('NOcommit1' , false);
    DOTHEINSERT('commit2' , true);
    DOTHEINSERT('NOcommit2' , false);
    DOTHEINSERT('commit3' , true);
    ROLLBACK;


end ;
/

select * from SHOW_TRANSACTION ;
/

MISC            
--------------- 
commit1         
COMMIT2         
commit3 

/* now the transaction is in a sub-sub procedure */


Without the source of the package this one could be tricky.

For starters, Oracle normally raises an exception if you do a COMMIT or ROLLBACK inside a package that is not marked with the AUTONOMOUS TRANSACTION pragma, regardless of the calling language.

So I presume that if the package contains a COMMIT and ROLLBACK then the package MUST be autonomous. This would mean that your client side rollback wouldn't have any impact.

If a package is autonomous then an exception is raised if you exit the package without having done either a ROLLBACK or COMMIT - i.e. there should be no route where the package could exit, leaving an uncommitted row on the database.

The only situation that could explain what you are seeing is if the rollback FAILED, or was not executed at all, and the code then carried on to COMMIT.

(Another possible option - the Insert has ALSO been done as an autonomous transaction, with a self-contained commit, so that the data was committed before the rollback?).

Autonomous transactions are notorious for (re)-introducing the problems that atomic transactions are there to avoid (race conditions, data integrity, deadlocks) - they have their uses, but must be handled with care.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜