Insert,Update em mais de uma tabela na MESMA operação(botão) (rollback em todas, caso um deles der erro!)
12/03/2019
0
Minha questão é simples mas preciso de uma resposta com exemplos e bem prática.
suponha que em uma determinada operação (ao clicar no botão "GRAVAR" por exemplo) eu faça um insert em uma tabela, e dois updates em outras duas tabelas. na mesma operação.
Como assegurar um rollback caso a operação venha a falhar em uma das 3 tabelas? Eu tenho uma vaga idéia de colocar um starttransaction no inicio da operacao mas nao sei como fazer...
Esta resposta ficará para consultas futuras, pois nao achei nada parecido no fórum.
Obrigado a quem colaborar.
Emerson
Posts
13/03/2019
Hélio Devmedia
Você precisa utilizar os métodos específicos dos seus componentes de acesso a dados para abrir uma transação com o banco.
Com DBExpress funciona assim?
var FIsolationLevel : TDBXIsolations; FTransaction : TDBXTransactions; begin //Abrir Transação FIsolationLevel := TDBXIsolations.Create; FTransaction := DMConnection.Conn1.BeginTransaction(FIsolationLevel.ReadCommitted); //guarde esta variável, ela é o id da transação e será necessária para comitar ou rollback; //usar normalmente os componentes... ClientDataSet.pos; ClientDataSet.applyUpdates(-1) sqlQuery.execute; //... todos os tipos de operações utilizando componentes de acesso a dados e queries; try Conn1.CommitFreeAndNil(FTransaction); except Conn1.RollbackFreeAndNil(FTransaction); end;
Espero ter ajudado, um forte abraço e fique com Deus.
26/03/2019
Emerson
veja abaixo parte do codigo em que duas tabelas sao afetadas na mesma operação. Como abraçar duas ou mais tabelas com as transactions ??
De modo que se uma delas dê erro seja feito rollback em todas ???
poderia me dar um exemplo utilizando o firedac /mysql ? Agradeço a quem ajudar.
// primeira tabela
QyAux.SQL.Clear;
QyAux.SQL.Add('INSERT INTO OS_andamento');
QyAux.SQL.Add('(OS,datahora,status)');
QyAux.SQL.Add('VALUES(:pOs, :pagora, :pstatus)');
QyAux.ParamByName('pos').AsString := edtBarCode.Text;
QyAux.ParamByName('pstatus').AsString := 'IS';
QyAux.ParamByName('pagora').AsDateTime :=Agora;
try
FrmMenuPrincipal.FDConnection1.txoptions.AutoCommit := false;
QyAux.ExecSQL;
FrmMenuPrincipal.FDConnection1.Commit;
FrmMenuPrincipal.FDConnection1.txoptions.AutoCommit := true;
except
on E: Exception do
begin
FrmMenuPrincipal.FDConnection1.Rollback;
FrmMenuPrincipal.FDConnection1.txoptions.AutoCommit := true;
showmessage('E R R O ! Repetir esta operação.' + #13 + #10 + stringOfChar('=', 65) + #13 + #10 + 'Apresenta Cartao' + #13 + #10 +
QyAux.SQL.Text + #13 + #10 + E.Message);
GravarLog('Apresenta Cartao' + #13 + #10 + QyAux.SQL.Text + #13 + #10 + E.Message);
abort;
end;
end;
// segunda tabela
QyAux.SQL.Clear;
QyAux.SQL.Text := 'Update OS set os_abertoem = :pagora,os_posicao=:pstatus ' + ' where idOS=' +QuotedStr(edtBarCode.Text);
QyAux.ParamByName('pagora').AsDateTime :=Agora;
QyAux.ParamByName('pstatus').AsString :='IS';
try
FrmMenuPrincipal.FDConnection1.txoptions.AutoCommit := false;
QyAux.ExecSQL;
FrmMenuPrincipal.FDConnection1.Commit;
FrmMenuPrincipal.FDConnection1.txoptions.AutoCommit := true;
except
on E: Exception do
begin
FrmMenuPrincipal.FDConnection1.Rollback;
FrmMenuPrincipal.FDConnection1.txoptions.AutoCommit := true;
showmessage('E R R O ! Repetir esta operação.' + #13 + #10 +
stringOfChar('=', 65) + #13 + #10 + 'Apresenta Cartao' + #13 + #10 +
QyAux.SQL.Text + #13 + #10 + E.Message);
GravarLog('Apresenta Cartao' + #13 + #10 + QyAux.SQL.Text + #13 + #10 +
E.Message);
abort;
end;
end;
31/03/2019
Hélio Devmedia
Desculpe a demora em responder...
Você precisa iniciar a transação com FDConnection1.StartTransaction e pode dando post normalmente. deixe o commit para o final. Todas as Queryes devem estar no mesmo bloco Try except com um FDConnection1.Commit antes do Except e não separadas.
Dentro do Except você deve fazer "ifs" para testar qual sql gerou o erro para mostrar o usuário, e em seguida dar FDConnection1.Rollback;
Espero ter ajudado.
Qualquer coisa, poste como ficou o novo código e avançaremos no seu problema!
Um forte abraço e fique com Deus.!
17/04/2019
Emerson
somente agora consegui retomar esta questão.
acredito que ficará assim:
...
FDConnection1.StartTransaction;
try
QYSs.ExecSQL;
QYIntd.ExecSQL;
QYVeic.ExecSQL;
FrmMenuPrincipal.FDConnection1.Commit;
except
on E: Exception do
begin
FrmMenuPrincipal.FDConnection1.Rollback;
mas... vc disse que eu vou colocar ifs para saber qual tabela deu erro... mas ao chegar nesta excessao, como eu vou saber quais das tabelas acima (QYSs,QYIntd ou QYVeic).... ocasionou a excessao ???
Obrigado pela atenção.
30/04/2019
Emerson
==================================
Bem, parece que está funcionando bem com sua dica, vou deixar postado aqui para futuras consultas.
SEMPRE QUE FOR DAR INSERT /UPDATE /DELETE em uma MESMA OPERACAO, deverá alimentar os FDQUERY (um para cada tabela)
Note que "alimentamos as FDQUERY sem dar o execsql...
// Insert OS_andamento...
QYAndamento.SQL.Clear;
QYAndamento.SQL.Add('INSERT INTO OS_andamento');
QYAndamento.SQL.Add('(OS,datahora,status,idFunc)');
QYAndamento.SQL.Add('VALUES(:pOs, :pagora, :pstatus,:pFuncionario)');
QYAndamento.ParamByName('pos').AsString := edtBarCode.Text;
QYAndamento.ParamByName('pstatus').AsString := 'IS';
QYAndamento.ParamByName('pagora').AsDateTime :=now();
QYAndamento.ParamByName('pFuncionario').AsString :=Mmecanico;
// Update em OS
QYOS.SQL.Clear;
QYOS.SQL.Text := 'Update OS set os_abertoem = :pagora,os_posicao=:pstatus ' + ' where idOS=' +QuotedStr(edtBarCode.Text);
QYOS.ParamByName('pagora').AsDateTime :=now();
QYOS.ParamByName('pstatus').AsString :='IS';
// Update em Funcionario para marcar O.S. e veiculo em aberto...
QyFunc.SQL.Clear;
QyFunc.SQL.Text := 'Update Funcionario set os_aberto = :pNumOs,os_veiculo=:pveiculo ' + ' where idFuncionario=:pFuncionario';
QyFunc.ParamByName('pNumOs').AsInteger :=StrToInt(edtBarCode.Text);
QyFunc.ParamByName('pveiculo').AsString :=mVeiculo;
QyFunc.ParamByName('pFuncionario').AsString :=mmecanico;
//Agora sim damos o execsql em todos juntos, se algum falhar toda as alteracoes sao abortadas... (rollback)
FrmMenuPrincipal.FDConnection1.StartTransaction;
try
QYAndamento.ExecSQL;
QYOS.ExecSQL;
QyFunc.ExecSQL;
FrmMenuPrincipal.FDConnection1.Commit;
except
on E: Exception do
begin
FrmMenuPrincipal.FDConnection1.Rollback;
showmessage('E R R O ! Repetir esta operação.' + #13 + #10 +stringOfChar('=', 65) + #13 + #10
+ 'Apresenta Cartao' + #13 + #10 +QyAux.SQL.Text + #13 + #10 + E.Message);
abort;
end;
end;
Application.MessageBox('OPERACAO REALIZADA COM SUCESSO...,'Aviso',mb_Ok+MB_ICONINFORMATION);
end;
Clique aqui para fazer login e interagir na Comunidade :)