VB OracleTransaction не откатывается

Я вызываю стороннюю хранимую процедуру в Oracle из VB, которая не откатывается.

Сначала код (я упрощаю):

Строка подключения:

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

Вызов (я только что принудительно откатился сразу после выполнения, чтобы проверить его):

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", 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()

Я не могу подробно рассказать о хранимой процедуре, но внутри она выполняет фиксацию и откат.

В любом случае, он выполняет вставку, и этот немедленный откат не отменяет вставку.

Любые идеи?


person Kamal    schedule 14.09.2010    source источник
comment
CREATE USER (или любой другой оператор DML, такой как GRANT, DROP, ALTER или любой другой, кроме SELECT, INSERT, UPDATE или DELETE) молча и неявно делает следующее: COMMIT; [run your statement]; COMMIT;   -  person Adam Musch    schedule 14.09.2010


Ответы (2)


Логика фиксации/отката в PL/SQL (независимо от предложения AUTONOMOUS TRANSACTION --> НЕ ИСПОЛЬЗУЙТЕ ЭТО, если вы не регистрируете ошибки: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:2212445691154)

Поэтому, если вы выдаете COMMIT в своем пакете, ваши данные фиксируются, PERIOD. Откат таким же образом.

Создайте таблицу для следующих примеров:

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

Глядя на этот пример, видно, что:

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   

Обратите внимание, что окончательный ROLLBACK ничего не делает? это потому, что COMMIT/ROLLBACKS в процедуре влияют на всю область действия, посмотрите на этот пример:

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     

Здесь пакет ROLLBACK удаляется, поэтому, когда происходит этот COMMIT, вставляется содержимое всех INSERTS до этого.

Если вы хотите, чтобы приложение VB обрабатывало транзакцию, вы должны удалить фиксацию/откат из PL/SQL.

Кроме того, не имеет значения, где находятся коммит/откат, они указывают на ВЕСЬ ОБЪЕМ всех элементов в транзакции:

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 

/* теперь транзакция находится в под-подпроцедуре */

person Harrison    schedule 14.09.2010
comment
Привет Танг. Так что в основном то, что я должен попросить третью сторону, это вообще НЕ фиксировать или откатывать. и мой vb должен полностью контролировать фиксацию и откат с моей стороны? - person Kamal; 14.09.2010
comment
@Kamal, если вы хотите обрабатывать область транзакций SQL, это именно то, что вам нужно сделать. Альтернатива уродлива тем, что можно оформить удаления самостоятельно (так как они уже коммитили) — но если будут менять, то непременно так и делайте. (в моих приложениях .Net я оставляю область транзакций приложению .Net и не выполняю коммиты/откаты из Oracle) - person Harrison; 14.09.2010
comment
Спасибо за решение. У меня нет глубокого опыта работы с Oracle, и я хотел получить окончательный ответ, а не возиться часами. Также не помогает отсутствие прямого доступа к s-procs. теперь более сложный вопрос - как убедить стороннего поставщика изменить свой код... - person Kamal; 14.09.2010
comment
@Kamal, удачи с этим. Я бы использовал такие слова, как «... вместо того, чтобы дать мне загадочный откат без уведомления (что может вызвать ошибку в моем приложении или заставить меня выполнить другой запрос, просто чтобы посмотреть, работает ли он, пусть ошибка всплывает до моего приложение и позвольте мне выполнить откат и выполнить мою логику, так как я буду знать, что элемент не удался...' также имейте в виду, что вам понадобится попытка/поймать и следить за исключением для обработки отката - person Harrison; 14.09.2010
comment
@Tanging - Спасибо. У меня есть гораздо более сложный набор кода с блоками try и catch. Я упростил это для вопроса. Спасибо за вашу помощь. - person Kamal; 14.09.2010
comment
@Tanging - обновление - можете в это поверить... они перешли на другую сторону... менее чем за 48 часов. Спасибо за вашу помощь. - person Kamal; 18.09.2010
comment
@Kamal, просто великолепно! Желаю, чтобы все третьи лица действовали так же быстро! - person Harrison; 21.09.2010

Без источника пакета это может быть сложно.

Во-первых, Oracle обычно вызывает исключение, если вы выполняете COMMIT или ROLLBACK внутри пакета, который не помечен прагмой AUTONOMOUS TRANSACTION, независимо от вызывающего языка.

Поэтому я предполагаю, что если пакет содержит COMMIT и ROLLBACK, то пакет ДОЛЖЕН быть автономным. Это будет означать, что ваш откат на стороне клиента не окажет никакого влияния.

Если пакет является автономным, то возникает исключение, если вы выходите из пакета, не выполнив ROLLBACK или COMMIT, то есть не должно быть маршрута, по которому пакет мог бы выйти, оставив незафиксированную строку в базе данных.

Единственная ситуация, которая могла бы объяснить то, что вы видите, — это если откат завершился FAILED или вообще не был выполнен, а затем код перешел к COMMIT.

(Еще один возможный вариант - Вставка ТАКЖЕ сделана как автономная транзакция, с автономным коммитом, чтобы данные были зафиксированы до отката?).

Автономные транзакции печально известны тем, что (повторно) создают проблемы, которых атомарные транзакции должны избегать (условия гонки, целостность данных, тупиковые ситуации) — у них есть свое применение, но с ними нужно обращаться осторожно.

person JulesLt    schedule 14.09.2010
comment
какое исключение вызывает Oracle, когда вы выполняете Commit/Rollback в пакете без прагмы AUTONOMOUS TRANSACTION? Я делаю это все время без вреда... см. пример выше, они работают с коммитами и без прагмы AUTONOMOUS TRANSACTION. Я переписал вышеуказанный аномальный блок в процедуру, и она отлично работает... - person Harrison; 14.09.2010
comment
Привет, Джулс, я понимаю, что ты говоришь. Как я могу определить, является ли он автономным (как он помечен). Насколько я знаю, в процедуре есть один или два базовых оператора вставки --> фиксация --> потом исключение ПРИ ДРУГИХ с откатом. И последний коммит перед концом. Это относится к тому, что я не могу откатиться с vb? - person Kamal; 14.09.2010
comment
Tanging - я не могу найти код ошибки, но это происходит только тогда, когда вы пересекаете языковые «уровни» в одной транзакции, то есть у вас есть код Java, который обновляет строку, а затем вызывает процедуру или код pl/sql, который вызывает в extproc C, который содержит коммит. (Второй пример отлично работает, если вы изолируете вызов extproc внутри автономной транзакции). - person JulesLt; 15.09.2010
comment
Конечно, я не знаю, вызывает ли VB такую ​​​​ошибку, или это одна из тех глупых платформ, которая решает автоматически зафиксировать после любой команды. - person JulesLt; 15.09.2010