GARANTIR DESCONTO

Fórum StartTransaction com ExecuteDirect #346684

25/09/2007

0

Boa noite pessoal!

Por favor, tirem uma dúvida minha. Quando chamamos o método ExecuteDirect do SQLConnection, para criar tabelas, campos etc, no bando de dados, não podemos fazê-lo em uma transação? pois caso o script tenha algum erro, podemos chamar o rollback.

Por exemplo, estou testando o seguinte:

var TD: TTransactionDesc;
begin
TD.TransactionID := 1;
TD.IsolationLevel := xilREADCOMMITTED;
try
Con.StartTransaction(TD);

Con.ExecuteDirect(´ALTER TABLE ALUGUEL ADD TAXA_FAXINA ´+
´NUMERIC(14,2) DEFAULT 0´);
Con.ExecuteDirect(´UPDATE ALUGUEL SET TAXA_FAXINA = 0´);

Con.Commit(TD);
except
Con.Rollback(TD);
raise;
end;
end;

Quando executo o bloco acima, o comando Update não atualiza o campo (TAXA_FAXINA) criado nos registros para 0.

Se chamo sem o StartTransaction, funciona.

O StartTransaction não pode ser chamado em casos como este?

Se alguém puder ajudar, ficarei muito grato!

Marcelo


Tchelllo

Tchelllo

Responder

Posts

25/09/2007

Nerdex

Fundamentalmente este tipo de ´administração/manutenção´ a nível de DML direto na base foge do escopo a transações, digamos com clientes. Acredito que deves ter observado o quesito : permissões de acesso neste seu SGDB apartir do sistema... ?


Responder

Gostei + 0

26/09/2007

Adriano Santos

Não é que não pode, é que nesse tipo de operação nem é necessário fazer, pois o ExecuteDirect aplica o Script independente de Commit ou não. Se você usar assim:
procedure TForm1.Button1Click(Sender: TObject);
var
  TD : TTransactionDesc;
  I : Integer;
begin
  SQLDataSet1.Close;
  ClientDataSet1.Close;

  SQLConnection1.ExecuteDirect(´ALTER TABLE TABELA1 ADD TESTE NUMERIC(15, 2) DEFAULT 0´);
  SQLConnection1.ExecuteDirect(´UPDATE TABELA1 SET TESTE = 1´);

  ClientDataSet1.Open;
end;

Vai perceber que funciona. As transações devem ser usadas em outras ocasiões. Recomendo dar uma boa lida nesses tópicos:

[quote:02b2fc9ff1=´Adriano Santos´]Velhinho, dá uma olhada neste tópico que tem uma discussão boa sobre o assunto. Vais entender com certeza.

[url=http://forum.clubedelphi.net/viewtopic.php?t=58547&highlight=sqldataset+++clientdataset]Transações com DbExpress de forma Bidirecional[/url]


E mais algumas coisas sobre DBExpress:
[url=http://forum.clubedelphi.net/viewtopic.php?t=75031&start=0&postdays=0&postorder=asc&highlight=&sid=6c3d12b7f2e7a711939b7662cd0834db]dbExpress Interbase 6.5 Delphi 7.0[/url]
[url=http://forum.clubedelphi.net/viewtopic.php?t=75051]Mestre/Detalhe dbExpress[/url]

:wink: :wink:[/quote:02b2fc9ff1]


Responder

Gostei + 0

26/09/2007

Tchelllo

E aí pessoal, obrigado pela atenção!!

Adriano, estava fazendo alguns testes com o exemplo que coloquei, para ver se a transação realmente fazia o rollback ou não, caso o script tivesse erros, e notei que ele faz o rollback.

no exemplo:

begin
Con.StartTransaction(TD);

Con.ExecuteDirect(´ALTER TABLE ALUGUEL ADD TAXA_FAXINA ´+
´NUMERIC(14,2) DEFAULT 0´);
Con.ExecuteDirect(´UPDATE ALUGUEL SET TAXA_FAXINA = A´);

Con.Commit(TD);
except
Con.Rollback(TD);
raise;
end;
end;

ao invés de no campo criado (TAXA_FAXINA) atualizar com o valor ´0´, coloquei o valor ´A´, que irá gerar uma excessão e vai entrar no except, pois trata-se de um campo numeric.

Ví que a aplicação faz o rollback e o campo e muito menos o UPDATE
não são aplicados no banco.

Caso não inicie a transação, o campo é criado, só o UPDATE que não é feito (isso neste exemplo, que insiro o valor ´A´).

Por isso não entendi quando vc disse que o ExecuteDirect vai aplicar o script independente de commit ou não. Nesse exemplo o rollback funcionou.

O que tb não estou entendendo é que quando aplico o script dentro de uma transação, o campo é criado mas o UPDATE não é feito. Se aplico sem transação o campo e o UPDATE são aplicados com sucesso.

Mais uma vez, obrigado!

Marcelo


Responder

Gostei + 0

26/09/2007

Adriano Santos

E aí pessoal, obrigado pela atenção!! Adriano, estava fazendo alguns testes com o exemplo que coloquei, para ver se a transação realmente fazia o rollback ou não, caso o script tivesse erros, e notei que ele faz o rollback. no exemplo:
begin
  try
    Con.StartTransaction(TD); 
    Con.ExecuteDirect(´ALTER TABLE ALUGUEL ADD TAXA_FAXINA ´+ ´NUMERIC(14,2) DEFAULT 0´); 
    Con.ExecuteDirect(´UPDATE ALUGUEL SET TAXA_FAXINA = A´); 
    Con.Commit(TD); 
  except 
    Con.Rollback(TD); 
    raise; 
  end; 
end; 
ao invés de no campo criado (TAXA_FAXINA) atualizar com o valor ´0´, coloquei o valor ´A´, que irá gerar uma excessão e vai entrar no except, pois trata-se de um campo numeric. Ví que a aplicação faz o rollback e o campo e muito menos o UPDATE não são aplicados no banco. Caso não inicie a transação, o campo é criado, só o UPDATE que não é feito (isso neste exemplo, que insiro o valor ´A´). Por isso não entendi quando vc disse que o ExecuteDirect vai aplicar o script independente de commit ou não. Nesse exemplo o rollback funcionou. O que tb não estou entendendo é que quando aplico o script dentro de uma transação, o campo é criado mas o UPDATE não é feito. Se aplico sem transação o campo e o UPDATE são aplicados com sucesso. Mais uma vez, obrigado! Marcelo

Vamos lá camarada, vamos ver se detalhando mais o processo fica mais fácil de entender.

[list:16d80da6e8]
[*:16d80da6e8]1. O método ExecuteDirect é pra ser usado sozinho, isolado e um comando de cada vez, ou seja, quando você faz o primeiro comando ele deve ser comitado se estiver dentro de uma transação. Se estiver usando em controle de transação o commit será dado automaticamente pelo método. Então pense na sua situação.
[list:16d80da6e8]
[*:16d80da6e8] a. Você mandou executar um [b:16d80da6e8]ALTER TABLE[/b:16d80da6e8].
[*:16d80da6e8] b. Sem comitar manou efetuar um [b:16d80da6e8]UPDATE[/b:16d80da6e8] no campo incluso.
[/list:u:16d80da6e8]
O que acontece nesse caso?
Erro. Como o [b:16d80da6e8]ALTER TABLE[/b:16d80da6e8] ainda não foi aplicado por causa do commit que não foi dado, o campo XXXX não existe na base.
Se estiver usando o [b:16d80da6e8]ExecuteDirect[/b:16d80da6e8] sem controle de transação, o seu [b:16d80da6e8]ALTER TABLE[/b:16d80da6e8] será aplicado automaticamente e o segundo comando não falhará.
[*:16d80da6e8] 2. Por outro lado se você aplicar o commit a cada situação, ou seja, a cada comando recebido pelo [b:16d80da6e8]ExecuteDirect[/b:16d80da6e8] você terá sucesso, pois a segunda vez que o [b:16d80da6e8]ExecuteDirect[/b:16d80da6e8] for chamado o seu [b:16d80da6e8]ALTER TABLE[/b:16d80da6e8] já terá adicionado o campo novo na base.
[/list:u:16d80da6e8]

A idéia de se usar transações é quando se usa os métodos [b:16d80da6e8]Append, Delete, Post e Cancel[/b:16d80da6e8] do [b:16d80da6e8]DataSet[/b:16d80da6e8] em um conjunto grande de instruções. Por exemplo:
Imagine que seu usuário inseriu 1 nota fiscal no sistema com 100 itens. O seu usuário clicou em [b:16d80da6e8]Gravar Nota[/b:16d80da6e8]. Nesse momento seu sistema deve:
[list:16d80da6e8]
[*:16d80da6e8]a. Debitar os itens do Estoque;
[*:16d80da6e8]b. Incluir um registro no Contas a Receber;
[*:16d80da6e8]c. Atualizar o fluxo de caixa com a previsão de saldo;
[*:16d80da6e8]d. Gerar automaticamente os boletos bancários;
[/list:u:16d80da6e8]
Nos processo A, B, C e D digamos que você tenha uma tabela para cada um deles. Isso significa que terá que inserir aproximandamente 1 registro em cada tabela, isso se não for gerar mais de boleto no caso de um pagamento parcelado.
Pois bem, você teria uma estrutura mais ou menos como esta no botão [b:16d80da6e8]Gravar Nota[/b:16d80da6e8]:

procedure TForm1.BotaaoGravarClick(Sender: TOject);
begin
  with DataModule do
  begin
    -> Localiza o Produto no Estoque;
    -> Altera, decrementa um da quantidade, grava, ApplyUpdates(0);
    -> Append, Post e ApplyUpdates(0) no ContasAReber;
    -> Append, Post e ApplyUpdates(0); no FluxoCaixa;
    -> Rotina Inclusão de Boletos
    -> -> for I := 0 to NumeroBoletos do
          begin
            Append;
            -> Dados do Boleto;
            Post;
            ApplyUpdates(0);
          end;
    -> Grava Item da Nota fiscal. ApplyUpdates(0);
    -> Grava Nota Fiscal. ApplyUpdates(0);
  end;
end;

Agora imagina que aconteça algum problema no meio de uma destas operações?
Você deve garantir que todos os registros de todas as tabelas sejam aplicados ou descartados. É ai que entra a Transação. Essa rotina ficaria mais ou menos assim:

procedure TForm1.BotaaoGravarClick(Sender: TOject);
var
  TD : TTransactionDesc;
begin
  Try
    TD.IsolationLevel := xilREADCOMMITTED;
    SQLConnection1.StartTransaction(TD);
    with DataModule do
    begin
      -> Localiza o Produto no Estoque;
      -> Altera, decrementa um da quantidade, grava, ApplyUpdates(0);
      -> Append, Post e ApplyUpdates(0) no ContasAReber;
      -> Append, Post e ApplyUpdates(0); no FluxoCaixa;
      -> Rotina Inclusão de Boletos
      -> -> for I := 0 to NumeroBoletos do
            begin
              Append;
              -> Dados do Boleto;
              Post;
              ApplyUpdates(0);
            end;
      -> Grava Item da Nota fiscal. ApplyUpdates(0);
      -> Grava Nota Fiscal. ApplyUpdates(0);
    end;
    SQLConnection1.Commit(TD);
  except on E:Exception do
    begin
      SQLConnection1.RollBack(TD);
      raise;
    end;
  end;
end;

Agora sim sua operação estará salva e faz algum sentido. Caso ocorra qualquer erro durante o processamento, todos os registros envolvidos na transação são apagados e/ou alterados para voltar ao estado normal.

Fiz um exemplinho básico incluindo 4 botões na tela. Add (Alter table), Update (Altera valores na tabela), Commit e RollBack. No onCreate do form abra a transacao e faça alguns testes.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DBXpress, DB, SqlExpr, StdCtrls;

type
  TForm1 = class(TForm)
    SQLConnection1: TSQLConnection;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    TD: TTransactionDesc;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  TD.TransactionID := 1;
  TD.IsolationLevel := xilREADCOMMITTED;
  SQLConnection1.StartTransaction(TD);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  SQLConnection1.ExecuteDirect(´ALTER TABLE TABELA1 ADD ORIGEM INTEGER´);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  SQLConnection1.Commit(TD);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  SQLConnection1.Rollback(TD);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  SQLConnection1.ExecuteDirect(´UPDATE TABELA1 SET ORIGEM=1´);
end;

end.



Responder

Gostei + 0

26/09/2007

Tchelllo

Adriano, muito obrigado pela sua atenção!!!
resposta muito bem detalhada!!

Abraços!


Responder

Gostei + 0

26/09/2007

Fabiano Góes

Fala ai Adriano blz.
cara parabéns pela explicação muito util para futuras dúvidas.

abraço !!!


Responder

Gostei + 0

27/09/2007

Adriano Santos

[quote:29ab17b733=´Fabiano Góes´]Fala ai Adriano blz.
cara parabéns pela explicação muito util para futuras dúvidas.

abraço !!![/quote:29ab17b733]
Quê isso gente, só sinto falta do cara que mais me ensinou DBExpress direta e indiretamente: [b:29ab17b733]Vinicius2K[/b:29ab17b733]. Alguém sabe dele? Sumiu, o cara manja muito.

Vlw, abs.


Responder

Gostei + 0

27/09/2007

Fabiano Góes

[quote:72808da3d0=´Adriano Santos´][quote:72808da3d0=´Fabiano Góes´]Fala ai Adriano blz.
cara parabéns pela explicação muito util para futuras dúvidas.

abraço !!![/quote:72808da3d0]
Quê isso gente, só sinto falta do cara que mais me ensinou DBExpress direta e indiretamente: [b:72808da3d0]Vinicius2K[/b:72808da3d0]. Alguém sabe dele? Sumiu, o cara manja muito.

Vlw, abs.[/quote:72808da3d0]

realmente o Vinicius2K manja mesmo, eu também tenho bastante dicas do Vinicius sobre DBExpress aprendi muito com ele.

abraço pra ele também !!!


Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar