Como trabalhar com multiplas transações utilizando dbExpress Framework

Olá pessoal, mais um post sobre dbExpress Framework, desta vez vamos focar em controle de transações. É comum termos situações onde precisamos ter mais de uma transação em uma mesma conexão ao banco de dados, essa tarefa no dbExpress é bem simples.

O método TDBXConnection.BeginTransaction inicia uma transação no banco de dados, o tipo desta transação irá depender do parâmetro a ser passado durante a criação da transação, estes tipos podem ser:

  • TDBXIsolations.ReadCommitted
  • TDBXIsolations.RepeatableRead
  • TDBXIsolations.DirtyRead
  • TDBXIsolations.Serializable
  • TDBXIsolations.SnapShot

Você pode consultar a documentação do RAD Studio online e entender cada tipo de isolamente transacional aqui. Importante lembrar que o isolamento transacional irá variar de banco para banco, verifica quais o seu banco de dados suporta.

Ao iniciar uma transação o método BeginTransaction retornará um objeto do tipo TDBXTransaction onde você poderá efetuar o Commit e Rollback da transação.

No exemplo abaixo temos duas transações onde através de uma efetuamos 5 inserts, o resultado da query mostra que os registros estão no banco de dados e não comitados ainda, a partir dai iniciamos outra transação com o nível de isolamento ReadCommited, que quer dizer trazer todos os registrados que estejam efetivamente “comitados” no banco, como ainda não fizemos o commit, o resultados do select virá fazio, ao final efetuamos o Rollback para que os registros não sejam efetivamente gravados na base de dados e depois efetuamos um commit na transação de consulta.

O código ficaria assim:

program MultipleTransaction;
{$APPTYPE CONSOLE}

uses
  SysUtils,
  DBXDynalink,
  DBXCommon,
  DBXInterbase;

Const
  InsertSQL : String = 'Insert Into Country Values ( ''%s'', ''%s'' )';

var
  ConnName: string;
  Conn: TDBXConnection;
  TransSelect,
  TransInsert  : TDBXTransaction;
  Cmd: TDBXCommand;
  Reader: TDBXReader;
  i : integer;

begin

  Conn := TDBXConnectionFactory.GetConnectionFactory.GetConnection
    ('employee ib', 'sysdba', 'masterkey');

  if Conn <> nil then
  begin

    Cmd := Conn.CreateCommand;

    // Start transaction - only inserts
    TransInsert := Conn.BeginTransaction(TDBXIsolations.ReadCommitted);

    for I := 1 to 5 do
    begin
      Cmd.Text := Format(InsertSQL, [ 'Record ' + IntToStr(I), IntToStr(I)]);
      Cmd.Prepare;
      Cmd.ExecuteUpdate;
    end;

    // Prepare and execute the SQL Statement
    Cmd.Text := 'SELECT * FROM Country Where Country Like ''Rec%''';
    Cmd.Prepare;

    Reader := Cmd.ExecuteQuery;

    Writeln('========== First Select including the new 5 records');
    while Reader.Next do
      Writeln(Reader.Value['Country'].GetAnsiString);

    // Start new transaction - doesn't include the inserted record
    TransSelect := Conn.BeginTransaction(TDBXIsolations.DirtyRead);

    Writeln('====================================================');
    Writeln('');

    Reader := Cmd.ExecuteQuery;

    Writeln('========== Second Select based on new transaction');
    while Reader.Next do
      Writeln(Reader.Value['Country'].GetAnsiString);

    // Commit Select transaction and Rollback the Insert transaction
    Conn.CommitFreeAndNil(TransSelect);
    Conn.RollbackFreeAndNil(TransInsert);

    Readln;
    Reader.Free;
    Cmd.Free;
    Conn.Free;

  end;

end.

Ao executar o código acima, temos o seguinte resultado:

17 respostas
  1. Emiliano Monteiro
    Emiliano Monteiro says:

    Prezado Sr. Adreano

    Bom dia

    O sr. conhece alguma ferramenta similar ao Genexus ou Maker que possa gerar o código do sistema modelado para Delphi?
    Ou seja uma ferramenta CASE para Delphi?

    já ví o x-maker mas achei desatualizado e não trabalha com a versão atual do delphi.

    grato,

    Prof. Emiliano Monteiro

    Responder
  2. Andreano Lanusse
    Andreano Lanusse says:

    Emiliano, se você procurar no Google “ferramenta case para delphi” encontrará várias opções. Eu não poderia recomendar alguma em específico, pois não sei o que você espera de uma ferramenta case.

    Eu particularmente não gosto de ferramentas cases, as que você citou geram uma falsa impressão de produtividade, pois depois a manutenção se torna difícil e custosa.

    O Delphi por si só oferece inúmeros recursos que permitem o desenvolvedor criar aplicações de alta qualidade com alta produtividade.

    Responder
  3. Carlos Eduardo Paulino
    Carlos Eduardo Paulino says:

    Andreano, muito obrigado por mais este artigo, algum tempo atraz estava preocupado pois não havia conseguido trabalhar isso no DBX4 e não encontrava a documentação.

    Responder
  4. Carlos Henrique Agnes
    Carlos Henrique Agnes says:

    Beleza Andreano!

    Seguinte, na linha 53, não deveria continuar o nível de isolamento ReadCommited?

    E sobre a intercalação de transações, como faço para começar duas transações, e escolher através de qual transação quero rodar um comando? Ouitro exemplo, em uma aplicação DataSnap, onde o objeto de conexão é compartilhado, como faço para o BeginTransaction de um cliente não interferir nos demais clientes?

    Ainda sobre o DataSnap, verifiquei que posso verificar qual usuário está rodando um comando verificando o ThreadID, este procedimento é seguro?

    Abraço,
    Tatu!

    Responder
    • Andreano Lanusse
      Andreano Lanusse says:

      Oi Carlos,

      Basta ter objetos transacionais diferentes. Em uma aplicação DataSnap você irá controlar transação no server method ou através de ClientDataSet, não tem conflito.

      Sobre o ThreadID sim, tudo no Datasnap é thread safe

      Responder
  5. Rodrigo Assis de Morais
    Rodrigo Assis de Morais says:

    Sr. Andreano,

    Multiplas transações em oracle utilizando Delphi 2007 eu não consigo fazer como você fez no seu artigo. Como faço nesse cenário ?

    Obrigado!

    Responder
  6. Clécio
    Clécio says:

    Bom dia a todos! Andreano poderia responder uma dúvida? Se tenho várias classes DAO que são responsáveis por consultas no banco, como poderia fazer da melhor forma para usar a DBXExpress Framework, teria que ter em todo método uma conexão, por ex.:

    *****método de pesquisa*****

    aDBXConn:= TDBXConnectionFactory.GetConnectionFactory.GetConnection
    (‘nomedaconexaodbxexpress’, ‘user’, ‘password’);

    aCmnd := aDBXConn.CreateCommand;

    aDBXTrans := aDBXConn.BeginTransaction(TDBXIsolations.ReadCommitted);

    // Start transaction
    aCmnd.Text := ‘sql’;

    aCmnd.Prepare;
    aReader := aCmnd.ExecuteQuery;

    …. continua….
    *****método para segunda pesquisa*****

    aDBXConn:= TDBXConnectionFactory.GetConnectionFactory.GetConnection
    (‘nomedaconexaodbxexpress’, ‘user’, ‘password’);

    …… continua

    ou teria outra forma melhor de implementar? Tipo criando uma classe de conexão, etc. Como sugestão poderia nos mostrar em um outro post como usar o DBXExpress Framework para Criar aplicações MVC.

    Grato e até mais…

    Responder
  7. Ozamir Frias
    Ozamir Frias says:

    boa tarde,

    excelente post, mas como ficaria a formatacao para um campo date inves de uma string

    InsertSQL : String = ‘Insert Into Country Values ( ”%s”, ”%s” )’;

    Responder
  8. Marlon
    Marlon says:

    Andreano,

    estou realizando a mesma Rotina que voce demonstrou, porém no meu caso aparesenta erro na linha 53;

    ” A transaction is already active.”

    Estou utilizando o Delphi 2010 – MYSQL 51.1.53 (INNODB)

    O que poderia ser ?

    Att,

    Responder
  9. Marlon
    Marlon says:

    Após varias consultas na documentação do Mysql:
    http://dev.mysql.com/doc/refman/5.1/en/dynindex-isolevel.html

    “Eu” não encontrei uma solução prática para meu problema.

    Ou seja, não tem como voce criar mais que uma transação na mesma sessão, para resolver o problema que eu tinha postado no tópico anterior, tive que criar uma nova sessão(Conexão) para cada transação que eu tinha.

    Na minha aplicação o usuário pode abrir abrir várias abas(TabSheet) – TDI e cada aba tem sua transacao independente uma da outra.
    Imagine duas abas de cadastro sendo alterada ao mesmo tempo, no modelo anterior o primeiro cadastro que executasse um COMMIT os dois cadastro em aberto eram comitados.

    para resolver o problema, tive que criar em cada Aba Aberta uma nova sessão no banco:
    Conexao := TDBXConnectionFactory.GetConnectionFactory.GetConnection(‘Falcon Financas’, ‘falcon’, ‘**********’);

    e apos fechar a aba matar a sessão ativa.

    Somente assim consegui resolver o problema de varias transaçoes ser executadas ao mesmo tempo, sem nenhuma interferir com a outra.

    Att, Marlon Nardi

    Responder
  10. Paulo Linhares
    Paulo Linhares says:

    Quanto as aplicações fireDAC, qual a forma correta de se gravar as informações no PostgreSQL e se tem algum artigo detalhando sobre esse assunto. Somente o Post() seria suficiente para gravar os dados. O FireDAC já faz todo resto automático?

    Responder

Trackbacks & Pingbacks

  1. […] This post was mentioned on Twitter by andreanolanusse. andreanolanusse said: Blog post: Como trabalhar com multiplas transações utilizando dbExpress Framework http://bit.ly/cJi2z6 #delphi […]

Deixe uma resposta

Want to join the discussion?
Feel free to contribute!

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *


Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.