Transação Firebird DBExpress
Pessoal estou com um problema na utilização de transação em firebird e DBExpress.
Seguinte, tenho que gravar informações em duas tabelas, e caso dê algum problema, não gravar em nenhuma.
Então faço o seguinte.
No ClientDataSet1 os registros já estão inseridos e ´Post´.
Então:
problema é que os dados do primeiro client são gravados no banco, mesmo estando dentro da transação o apply;
Seguinte, tenho que gravar informações em duas tabelas, e caso dê algum problema, não gravar em nenhuma.
Então faço o seguinte.
No ClientDataSet1 os registros já estão inseridos e ´Post´.
Então:
InicioTransacao. try ClientDataSet1.ApplyUpdates(-1); ClientDataSet2.Insert; PreencheClientDataSet2; ClientDataSet2.Post; ClientDataSet2.ApplyUpdates(-1); Commit; except RoolBack; end;
problema é que os dados do primeiro client são gravados no banco, mesmo estando dentro da transação o apply;
Andremuller
Curtidas 0
Respostas
Vinicius2k
29/03/2006
Colega,
O método ApplyUpdates do TClientDataSet nunca gera exceção. Você precisa ´amarrar´ o Commit ou Rollback da transação ao número de erros ocorridos. Um exemplo:
Outras dúvidas sobre transação com dbExpress podem ser esclarecidas usando a ferramenta de pesquisa do fórum.
Como exemplo, este tópico:
http://forum.clubedelphi.net/viewtopic.php?t=58547
O método ApplyUpdates do TClientDataSet nunca gera exceção. Você precisa ´amarrar´ o Commit ou Rollback da transação ao número de erros ocorridos. Um exemplo:
{ ... }
var
TudoOK: Boolean;
Transacao: TTransactionDesc;
begin
try
{ **** Iniciando a transação **** }
Transacao.TransactionID:= 1;
Transacao.IsolationLevel:= xilReadCommitted;
SeuSQLConnection.StartTransaction(Transacao);
{ **** Aplicando os updates **** }
if ClientDataSet1.ApplyUpdates(0) = 0 then
begin
ClientDataSet2.Insert;
PreencheClientDataSet2;
ClientDataSet2.Post;
if ClientDataSet2.ApplyUpdates(0) = 0 then
TudoOK:= True;
// TudoOK só será true se não houver erro em nenhum Update
end;
{ **** Confirmando ou voltando a transação **** }
if TudoOK then
SeuSQLConnection.Commit(Transacao)
else
SeuSQLConnection.Rollback(Transacao);
except
// Ocorreu uma exceção qualquer no bloco ...
SeuSQLConnection.Rollback(Transacao);
end;
end;Outras dúvidas sobre transação com dbExpress podem ser esclarecidas usando a ferramenta de pesquisa do fórum.
Como exemplo, este tópico:
http://forum.clubedelphi.net/viewtopic.php?t=58547
GOSTEI 0
Rodolfo.pirolo
29/03/2006
Só pegando uma carono no problema alheio.
Digamos que estes dois clientdatsets referem-se a pedido e itens do pedido. Até aí beleza, só que preciso no momento da gravação destes dar baixa do meu estoque.
Tem como fazer utilizando esta mesma estrutura?
Atenciosamente,
Rodolfo
Digamos que estes dois clientdatsets referem-se a pedido e itens do pedido. Até aí beleza, só que preciso no momento da gravação destes dar baixa do meu estoque.
Tem como fazer utilizando esta mesma estrutura?
Atenciosamente,
Rodolfo
GOSTEI 0
Adriano Santos
29/03/2006
Só pegando uma carono no problema alheio.
Digamos que estes dois clientdatsets referem-se a pedido e itens do pedido. Até aí beleza, só que preciso no momento da gravação destes dar baixa do meu estoque.
Tem como fazer utilizando esta mesma estrutura?
Atenciosamente,
Rodolfo
Claro [b:1305852a2c]rodolfo.pirolo[/b:1305852a2c], como o [b:1305852a2c]Vinicius2K[/b:1305852a2c] disse:
Você precisa ´amarrar´ o Commit ou Rollback da transação ao número de erros ocorridos.
No momento em que estiver gravando informações nos dois ClientDataSet´s você também pode elaborar uma rotina para gravar no Estoque, ou seja, dar o UpplyUpdates nas tabelas de estoque e testar se estes apply´s foram bem sucedidos, veja no exemplo do [b:1305852a2c]Vinicius2k[/b:1305852a2c] em outro tópico:
var TudoOK: Boolean; Transacao: TTransactionDesc; begin TudoOK:= False; Transacao.TransactionID:= 1; Transacao.IsolationLevel:= xilReadCommitted; SQLConnection1.StartTransaction(Transacao); // Aplicando os updates if ClientDataSet1.ApplyUpdates(0) = 0 then if ClientDataSet2.ApplyUpdates(0) = 0 then if ClientDataSet3.ApplyUpdates(0) = 0 then if ClientDataSet4.ApplyUpdates(0) = 0 then TudoOK:= True; // Note que TudoOK só será true se não houver nenhum erro em nenhum dos Updates if TudoOK then begin SQLConnection1.Commit(Transacao); ShowMessage(´Atualizações OK.´); end else begin SQLConnection1.Rollback(Transacao); ShowMessage(´Ocorreram erros. Alterações descartadas.´); end; end;
Aki o TudoOK só ficará True se todos os ApplyUpdates forem OK.
Tô certo [b:1305852a2c]Vinicius[/b:1305852a2c]???
GOSTEI 0
Rodolfo.pirolo
29/03/2006
Adriano,
Desculpe-me, acho que não fui claro na minha questão.
Minha dúvida é a seguinte:
Gostaria de montar uma atualização desta maneira:
...
if ClientDataSet2.ApplyUpdates(0) = 0 then
Para cada item do meu CDS_Item_pedidos
update estoque set qtde_estoque = qtde_estoque - qtde_vendida
ApplyUpdates
Se tudo terminar bem, commit
senão rollback em tudo.
Isto é possivel? Ainda não sei como atualizar o estoque com applyupadates, porque para esta rotina estou usando Store Procedure. Talvez criar um cds para atualizá-lo.
Atenicosamente,
Rodolfo
Desculpe-me, acho que não fui claro na minha questão.
Minha dúvida é a seguinte:
Gostaria de montar uma atualização desta maneira:
...
if ClientDataSet2.ApplyUpdates(0) = 0 then
Para cada item do meu CDS_Item_pedidos
update estoque set qtde_estoque = qtde_estoque - qtde_vendida
ApplyUpdates
Se tudo terminar bem, commit
senão rollback em tudo.
Isto é possivel? Ainda não sei como atualizar o estoque com applyupadates, porque para esta rotina estou usando Store Procedure. Talvez criar um cds para atualizá-lo.
Atenicosamente,
Rodolfo
GOSTEI 0
Renatacoimbra
29/03/2006
Entrando no assunto.
usando o Exemplo do colega Vinicius2K, basta vc dar baixa no seu estoque e só gravar em memoria usando o Post.
depois vc usa o ApplyUpdate, e se o ApplyUpdate for bem sucedido vc comita.
[]´s
usando o Exemplo do colega Vinicius2K, basta vc dar baixa no seu estoque e só gravar em memoria usando o Post.
depois vc usa o ApplyUpdate, e se o ApplyUpdate for bem sucedido vc comita.
[]´s
GOSTEI 0
Vinicius2k
29/03/2006
Colegas,
Particularmente, eu prefiro manter a baixa de estoque como uma trigger ´After Insert´ na tabela de ítens. É mais prático do que Stored Procedure, na minha opinião.
Porém, se você não desejar ou não puder deixar esta regra do negócio no SGBD. Pode implementar algo parecido com isto:
Particularmente, eu prefiro manter a baixa de estoque como uma trigger ´After Insert´ na tabela de ítens. É mais prático do que Stored Procedure, na minha opinião.
Porém, se você não desejar ou não puder deixar esta regra do negócio no SGBD. Pode implementar algo parecido com isto:
var TudoOK: Boolean; Transacao: TTransactionDesc; I: Integer; begin TudoOK:= False; // Definindo instrução para o update do estoque SQLDataSet1.CommandText := ´update ESTOQUE set QTDE = QTDE - :venda where IDPRODUTO = :idproduto´; Transacao.TransactionID:= 1; Transacao.IsolationLevel:= xilReadCommitted; SQLConnection1.StartTransaction(Transacao); // Aplicando os updates if ClientDataSet1.ApplyUpdates(0) = 0 then begin if ClientDataSet2.ApplyUpdates(0) = 0 then begin try for I := 0 to ClientDataSet2.RecordCount - 1 do begin // Atualizando o estoque. SQLDataSet1.ParamByName(´venda´).AsInteger := ClientDataSet2.FieldByName(´qtde´).AsInteger; SQLDataSet1.ParamByName(´idproduto´).AsInteger := ClientDataSet2.FieldByName(´idproduto´).AsInteger; SQLDataSet1.ExecSQL; end; TudoOK := True; except // Erro ao atualizar o estoque TudoOK := False; end; end; end; // Note que TudoOK só será true se não houver nenhum erro em nenhum dos Updates if TudoOK then begin SQLConnection1.Commit(Transacao); ShowMessage(´Atualizações OK.´); end else begin SQLConnection1.Rollback(Transacao); ShowMessage(´Ocorreram erros. Alterações descartadas.´); end; end;
GOSTEI 0
Rodolfo.pirolo
29/03/2006
Vinicius,
Corrija-me se estiver errado, quando mando executar a instrução sql de atualização do estoque conforme voce demonstrou, caso der um erro, quando executar o rollback, ele não retornará os valores anteriores.
Exemplo:
1° registro: atualizado com sucesso.
2° registro: atualizado com sucesso.
3° registro: erro na atualização.
Neste caso o rollback não alterará os valores do primeiro e segundo lançamentos.
Estou certo ou errado?
Abraços
Rodolfo
Corrija-me se estiver errado, quando mando executar a instrução sql de atualização do estoque conforme voce demonstrou, caso der um erro, quando executar o rollback, ele não retornará os valores anteriores.
Exemplo:
1° registro: atualizado com sucesso.
2° registro: atualizado com sucesso.
3° registro: erro na atualização.
Neste caso o rollback não alterará os valores do primeiro e segundo lançamentos.
Estou certo ou errado?
Abraços
Rodolfo
GOSTEI 0
Vinicius2k
29/03/2006
Nao...
Tudo o que você faz envolto na mesma transação é afetado pelo commit ou rollback.
Você poderia ter centenas de updates que, se eles estiverem todos dentro da mesma transação (que é o nosso caso), ao ser dado o rollback, tudo seria desfeito, incluindo triggers e SPs executadas pelo SGBD.
Fique tranquilo quanto a isso. ;)
Tudo o que você faz envolto na mesma transação é afetado pelo commit ou rollback.
Você poderia ter centenas de updates que, se eles estiverem todos dentro da mesma transação (que é o nosso caso), ao ser dado o rollback, tudo seria desfeito, incluindo triggers e SPs executadas pelo SGBD.
Fique tranquilo quanto a isso. ;)
GOSTEI 0
Rodolfo.pirolo
29/03/2006
Vinicius
Obrigado, funcionou belezinha.
Só desculpe-me pela demora da resposta, somente hoje pude testar a sua idéia.
Obrigado também ao Adriano Santos e a Renata Coimbra.
Abraços,
Rodolfo
Obrigado, funcionou belezinha.
Só desculpe-me pela demora da resposta, somente hoje pude testar a sua idéia.
Obrigado também ao Adriano Santos e a Renata Coimbra.
Abraços,
Rodolfo
GOSTEI 0