terça-feira, 7 de novembro de 2017

DROP Wiki #4 - Transações

O post de hoje é extremamente simples, mas sobre algo muito importante: Transações!




O sistema de transações do DROP trabalha com o conceito de chamadas cumulativas. E o que isto quer dizer?

Nota: O exemplo a seguir é uma versão resumida do que podemos encontrar em produção, mas demonstra bem o conceito do sistema de transações do DROP (não queime neurônios discutindo se você resolveria com uma estrutura de classes diferentes ou não, se concentre no recurso apresentado).


Começaremos com uma classe de nome TProduto. Esta possui um método que, entre outros, trata a movimentação do estoque deste produto. Toda movimentação deve atualizar o campo de saldo de estoque do produto, e também incluir um registro de detalhamento da movimentação. Este método deve ser auto-suficiente, e consequentemente, se responsabilizar pela garantia de que os dados armazenados são consistentes, o que com certeza demandará o uso de transação com o banco, concorda? Se você concorda, este método seria escrito mais ou menos assim:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
procedure TProduto.Movimentar(const pIDDocumento: UInt32; 
  const pMovimentacao: Currency);
begin
  ConexaoDoDROP.StartTransaction;

  try
    ConexaoDoDROP.ExecuteCommand('update estoque_produto ...');
    ConexaoDoDROP.ExecuteCommand('insert into movimento_estoque ...');

    ConexaoDoDROP.CommitTransaction;
  except
    ConexaoDoDROP.RollbackTransaction;
    raise;
  end;
end;

Pois bem, imagine que outra classe, de nome TVenda, possui um método responsável por consolidar uma venda de produtos no banco de dados. Este método registra os dados da venda em diversas tabelas, e como neste momento a venda está sendo consolidada, o estoque dos produtos também deve ser movimentado. Como bom programador, você deve estar pensando em reutilizar o método anterior para persistir a nova posição do estoque, certo? Vamos ao código de TVenda.Consolidar:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
procedure TVenda.Consolidar;
var
  lItem: TVendaItem;
begin
  ConexaoDoDROP.StartTransaction;

  try
    ConexaoDoDROP.ExecuteCommand('insert into venda ...');

    for lItem in Itens do
    begin
      ConexaoDoDROP.ExecuteCommand('insert into venda_item ...');
      lItem.Produto.Movimentar(Self.ID, lItem.Quantidade);
    end;

    ConexaoDoDROP.CommitTransaction;
  except
    ConexaoDoDROP.RollbackTransaction;
    raise;
  end;
end;

Muitos desenvolvedores optam por esta solução. No entanto, o que acontece com a sua engine de acesso a dados se você chamar uma segunda vez o comando de início de transação, sem ter terminado a transação anterior? Algumas engines não suportam esta técnica, e portanto, várias alternativas de workaround normalmente são implementadas, como testar se a conexão já possui uma transação aberta, ou delegar a abertura da transação para outro método, entre outras.

O sistema de chamadas cumulativas de transações do DROP permite que o comando de início da transação possa ser chamado mais de uma vez, sem que tenha que existir o desfecho da transação entre estas chamadas. Claro que, para que este sistema faça sentido, todas as chamadas de início de transação devem ser finalizadas também cumulativamente.

Concluindo, o DROP permite que, tanto o código de TProduto.Movimentar possa ser chamado individualmente, quanto possa ser reutilizado em outras rotinas já com transação aberta, sem que você precise escrever qualquer desvio para que isto tudo aconteça.

Era isto, até o próximo post!

Episódio Anterior Próximo Episódio

2 comentários:

  1. Para o segundo caso, ele só vai realizar o COMMIT das movimentações de estoque do produto no COMMIT das rotinas de TVENDA?

    ResponderExcluir

Você está fazendo isso errado! Tópico #2

 Fala galera! Como estão todos? Sejam bem-vindos ao primeiro post de 2021. Continuando o tema "Você está fazendo isso errado", va...