Array
(
)

Controlando erros em uma venda para evitar inconsistências

Valdirdill
   - 31 ago 2004

Trabalho com Firebird 1.5 e utilizo o DBExpress para relacionamentos com o banco de dados.
Quando eu gravo uma venda, faço alterações em várias tabelas (na própria venda, no produtos, ctas receber, etc).
Os últimos comandos da rotina de gravação da venda são assim:

try
EstoqueProdutos. ApplyUpdates(0);
ContasReceber.ApplyUpdates(0);
VendaMestre.ApplyUpdates(0);
except
ShowMessage(´ocorreu um erro´);

Até aqui tudo certo. Agora vem minha dúvida/problema: na rotina acima, dentro do try, há três comandos. Se o primeiro comando (EstoqueProdutos.Appp...) der erro, nada é gravado. Mas e se por exemplo, ocorrer um erro no no último comando dentro do try (VendaMestre.app...), as outras duas tabelas teriam sido alteradas indevidamente, pois a venda não foi gravada devido ao erro.
Pergunto: como controlar isso? Como ficaria uma rotina correta para isso?

Obrigado


Macario
   - 31 ago 2004

olá colega bom dia.

Bom não manjo muito de SQL, mas procure no forum topicos sobre Transações. Toda essa rotina de gerar a nota deve ficar dentro de uma transação, assim se em algum ponto houver falha será aplicado um rollback em tudo.

E aguarde mais explicações dos nossoa colegas.


Xtreme
   - 31 ago 2004

try
EstoqueProdutos. ApplyUpdates(0);
ContasReceber.ApplyUpdates(0);
VendaMestre.ApplyUpdates(0);
except
ShowMessage(´ocorreu um erro´);
transaction.rollback;//desta forma vc digamos assim cancela toda e qualquer alteracao feita no banoc de dados
end;


Xtreme
   - 31 ago 2004


Citação:
try
EstoqueProdutos. ApplyUpdates(0);
ContasReceber.ApplyUpdates(0);
VendaMestre.ApplyUpdates(0);
except
ShowMessage(´ocorreu um erro´);
transaction.rollback;//desta forma vc digamos assim cancela toda e qualquer alteracao feita no banco de dados
end;


Obs.: o transaction é um componente ex.: IBTransaction (na paleta do interbase).


Vinicius2k
   - 31 ago 2004

Colega,

Existem 2 problemas :
1. Se não houver controle explícito de transação muita coisa pode dar errado. O que for aplicado sem erros não é desfeito, pois está existindo uma transação diferente para cada ApplyUpdates...
2. O método ApplyUpdates NUNCA gera exceção para erros vindos do banco de dados... então try/except não resolve.

O que vc precisa fazer é controlar a transação e verificar sempre o valor de retorno do método ApplyUpdates (ele retorna o número de erros ocorridos na tentativa de aplicação)...
Um exemplo seria :
#Código

var 
TudoOK: Boolean;
TD: TransactionDesc;
try
TudoOK:= False;
TD.TransactionID:= 1;
TD.IsolationLevel:= xilReadCommitted;
SQLConnection1.StartTransaction(TD);
{****}
if EstoqueProdutos.ApplyUpdates(0) = 0 then
if ContasReceber.ApplyUpdates(0) = 0 then
if VendaMestre.ApplyUpdates(0) = 0 then
TudoOK:= True;
{****}
if TudoOK then SQLConnection1.Commit(TD)
else
begin
ShowMessage(´Ocorreram erros !´);
SQLConnection1.Rollback(TD);
end;
except
On E: Exception do
ShowMessage(´Não foi possível abrir a transação.´ + #13 + E.Message);
end;


Vc pode fazer uma pesquisa aqui no fórum sobre Transação + dbExpress q vc terá outros exemplos... veja tbm este tópico recente: http://delphiforum.icft.com.br/forum/viewtopic.php?t=50822

Espero ter ajudado...
T+


Xtreme
   - 31 ago 2004

Uma pequena duvida Vinicius2k, da forma que esta seu exemplo no momneto do commit/rollback todas as transacoes serao fechadas ou somente aquelas com a qual vc esta fazendo no seu exemplo?


Vinicius2k
   - 31 ago 2004

Somente ela...
Commit(TD) : o record ´TD´ tem a ´TransactionID´ que identifica a transação que vc quer dar start, commit ou rollback, mas isto só vale para dbExpress pq a SQLConnection suporta várias transações simultâneas...

Se vc estiver usando IBX e quiser trabalhar com múltiplas transações simultâneas, precisa de múltiplos IBTransactions... OK?

T+


Xtreme
   - 31 ago 2004

Beleza vinicius2k valew pela explicação cara! Falow.