[firebase-br] [OFF] Select dentro de uma transação utilizando o drive UIB está influenciando no rollback.

Junior Miranda jrmiran em gmail.com
Seg Ago 16 11:54:59 -03 2010


Observem este código de um exemplo simples:

var
T_ID1: TTransactionDesc;
begin
  //-
  T_ID1.TransactionID  := 1;
  T_ID1.IsolationLevel := xilREADCOMMITTED;
  SQLConnection1.StartTransaction(T_ID1);

  //-
  ClientDataSet1.Open;
  ClientDataSet1.First;
  //-
  try
    while not (ClientDataSet1.Eof) do
      begin
        //-
        SqlQuery1.Close;
        SqlQuery1.Sql.Text := 'SELECT CAB_NUM FROM CABECALHO WHERE CAB_ID = 
' + QuotedStr(IntToStr(ClientDataSet1IT_FKCAB_ID.AsInteger));
        SqlQuery1.open;

        //-
        SQLQuery2.Close;
        SQLQuery2.SQL.Text := 'UPDATE ITENS SET IT_NUM =' + 
QuotedStr(IntToStr(SqlQuery1.Fields.Fields[0].AsInteger + 1)) +  ' WHERE 
IT_FKCAB_ID =' + QuotedStr(IntToStr(ClientDataSet1IT_FKCAB_ID.AsInteger));
        SQLQuery2.ExecSQL();

        //-
        SQLQuery3.Close;
        SQLQuery3.SQL.Text := 'UPDATE CABECALHO SET CAB_NUM =' + 
QuotedStr(IntToStr(SqlQuery1.Fields.Fields[0].AsInteger + 1)) +  ' WHERE 
CAB_ID =' + QuotedStr(IntToStr(ClientDataSet1IT_FKCAB_ID.AsInteger));
        SQLQuery3.ExecSQL();

        //-
        ClientDataSet1.Next;
      end;
  Raise Exception.Create('');
  SQLConnection1.Commit(T_ID1);
  except
    SQLConnection1.Rollback(T_ID1);
  end;

O raise que estou utilizando para simular uma excessão, nos levará ao 
rollback. Mas digamos que 3 registros tenham sido alterados. O rollback não 
alcança o dois primeiros.
Explico:
O select executado na segunda volta do laço, comitta os ExecSql 
anteriores(Executados na primeira volta). O select executado na terceira 
volta do laço, comitta os ExecSql anteriores(Executados na segunda volta). 
Já na última volta, como chegamos ao final do laço, não ocorrerá um novo 
select. Com o raise, vamos ao except. Só que na verdade só existe um 
registro pendente (O último). Os dois primeiro foram commitados pela 
execussão do select. O select commita mas mantém a transação aberta. Com 
drive Interbase por exemplo, funciona normal! Ou seja, ao final, com  o 
raise, o rollback ocorrerá sobre todos os registro mencionados.

[]'s

Júnior Miranda.
--------------------------------------------------
From: "Eduardo Pombo" <eduardo em embras.net>
Sent: Monday, August 16, 2010 10:53 AM
To: "FireBase" <lista em firebase.com.br>
Subject: Re: [firebase-br][OFF] Select dentro de uma transação utilizando o 
drive UIB está influenciando no rollback.

> Acredito que o problema seja pq no momento que o erro ocorre a
> transacao ainda nao esteja criada.
> ex: se o erro ocorrer neste item abaixo a transacao ainda nao foi
> criada e ai vai para o except e com isso o rollback nao vai funcionar
> por nao ter transacao criada.
>
>       ClientDataSet1.Edit;
>       ClientDataSet1IT_NUM.AsInteger  := 
> SqlQuery2.Fields.Fields[0].AsInteger;
>       ClientDataSet1.Post;
>
> sugestao, mova o bloco abaixo para antes dos post e execsql.
>
> //-
> T_ID1.TransactionID  := 1;
> T_ID1.IsolationLevel := xilREADCOMMITTED;
> SQLConnection1.StartTransaction(T_ID1);
> //-
>
>
>
> Abraco,
>
> Espero ter ajudado
>
> Em 16 de agosto de 2010 09:03, Junior Miranda <jrmiran em gmail.com> 
> escreveu:
>> Senhores, bom dia!
>>
>> Desculpem-me pela natureza OFF do post. Mas, é que já rodei por todos os 
>> lados e não encontrei nenhuma solução que não seja substituir o drive 
>> UIB.
>> Mas infelizmente não posso fazer esta substituição neste momento. O 
>> problema é que como o select está dentro da transação e em loop, a cada 
>> volta,
>> ele (o select), commita o(s) ExecSql anterior(es). Isto antes do commit 
>> propriamente dito. Então, quando há uma excessão, o rollback não funciona 
>> como devido.
>> Quero garantir a atomicidade. Mas o bendito drive UIB não permite(Sob 
>> esta condição). Como não posso mudar o drive no momento, preciso 
>> encontrar uma
>> alternativa(na aplicação). Mas até agora nada funcionou.
>>
>> O código é este:
>> //------------
>> var
>> T_ID1: TTransactionDesc;
>> begin
>>  //-
>>  ClientDataSet1.Open;
>>  ClientDataSet1.First;
>>  //-
>>  try
>>    while not (ClientDataSet1.Eof) do
>>      begin
>>        //-
>>        SqlQuery2.Close;
>>        SqlQuery2.Sql.Text := 'SELECT CAB_NUM FROM CABECALHO WHERE CAB_ID 
>> = ' + QuotedStr(IntToStr(ClientDataSet1IT_FKCAB_ID.AsInteger));
>>        SqlQuery2.open;
>>
>>        ClientDataSet1.Edit;
>>        ClientDataSet1IT_NUM.AsInteger  := 
>> SqlQuery2.Fields.Fields[0].AsInteger;
>>        ClientDataSet1.Post;
>>
>>        //-
>>        SQLQuery1.Close;
>>        SQLQuery1.SQL.Text := 'UPDATE CABECALHO SET CAB_NUM =' + 
>> QuotedStr(IntToStr(SqlQuery2.Fields.Fields[0].AsInteger + 1)) +  ' WHERE 
>> CAB_ID =' + QuotedStr(IntToStr(ClientDataSet1IT_FKCAB_ID.AsInteger));
>>        SQLQuery1.ExecSQL();
>>
>>        //-
>>        ClientDataSet1.Next;
>>      end;
>>  //-
>>  T_ID1.TransactionID  := 1;
>>  T_ID1.IsolationLevel := xilREADCOMMITTED;
>>  SQLConnection1.StartTransaction(T_ID1);
>>  //-
>>  if ClientDataSet1.ApplyUpdates(0) <> 0 then
>>    Raise Exception.Create('');
>>  //-
>>  SQLConnection1.Commit(T_ID1);
>>  except
>>    SQLConnection1.Rollback(T_ID1);
>>  end;
>> //-------
>> Onde há o objeto ClientDataset1, eu também já utilizei um terceiro 
>> TSqlQuery para fazer um update(Ou seja, só com objetos TSqlQuery). Alguém 
>> já passou por isso e conseguiu contornar a questão do select dentro de um 
>> laço em uma transação com Drive UIB?
>>
>> []'s
>> ______________________________________________
>> FireBase-BR (www.firebase.com.br) - Hospedado em www.locador.com.br
>> Para saber como gerenciar/excluir seu cadastro na lista, use: 
>> http://www.firebase.com.br/fb/artigo.php?id=1107
>> Para consultar mensagens antigas: http://firebase.com.br/pesquisa
>>
>
>
>
> -- 
>
> Atenciosamente
>
> José Eduardo Pombo de Barros
> Gerente de Manutenção de Sistemas
>
> ______________________________________________
> FireBase-BR (www.firebase.com.br) - Hospedado em www.locador.com.br
> Para saber como gerenciar/excluir seu cadastro na lista, use: 
> http://www.firebase.com.br/fb/artigo.php?id=1107
> Para consultar mensagens antigas: http://firebase.com.br/pesquisa
> 




Mais detalhes sobre a lista de discussão lista