Transação


          Uma transação, em qualquer sistema, consiste em uma sequência de ações que são consideradas “atômicas”, ou seja, indivisíveis no conceito de trabalho.

Toda transação deve seguir o conceito de ACID (Atomicity, Consistency, Isolation e Durability  - Atomicidade, Consistência, Isolamento e Durabilidade). Em termos gerais:

Atomicidade: A execução da transação é atômica. Ou seja, todas as ações são executadas ou nenhuma;

Consistência: Cada execução deve conservar a consistência do banco de dados;

Isolamento: Cada transação deve ser isolada dos efeitos de execução concorrentes de outras transações e;

Durabilidade: Toda transação que for finalizada de forma bem sucedida deve persistir os seus resultados no sistema.

Transações no Protheus


Atenção

As funções BeginTran() e EndTran() tem seu uso proibido no Protheus, e não devem ser utilizadas em nenhuma hipótese.


         No Protheus, o controle de transações é iniciado através do comando BEGIN TRANSACTION e finalizado através do comando END TRANSACTION.

Para garantir a atomicidade da transação, dentro de uma sequencia iniciada por BEGIN TRANSACTION, todos os dados são gravados ou nenhum. 

Exemplo:

Function Grava01()

BEGIN TRANSACTION
 
	//-------------------------------------------------------------------
	//Bloco de Gravação A
	//Dentro deste bloco será realizado alguma gravação no banco de dados
	//-------------------------------------------------------------------

	Grava02()

END TRANSACTION

Return 

Function Grava02()

BEGIN TRANSACTION

	//-------------------------------------------------------------------
	//Bloco de Gravação B
	//Dentro deste bloco será realizado alguma gravação no banco de dados
	//-------------------------------------------------------------------

END TRANSACTION 


Return 

No exemplo acima, caso exista um erro na rotina Grava02() ou até mesmo na Grava01(), nenhum dado será inserido no banco de dados do sistema.

A Função DisarmTransaction

A função DisarmTransaction() pode ser utilizada para forçar o RollBack dos dados já inseridos e também evitar a gravação dos dados posteriores, protegidos desde a primeira chamada do comando BEGIN TRANSACTION. Esta função deixa o sistema no estado de TTSBREAK e, a partir deste ponto, todas as transações são desfeitas, até o primeiro nível de transação aberto.

No exemplo a seguir:

Function Grava01()

BEGIN TRANSACTION

	//-------------------------------------------------------------------
	//Bloco de Gravação A
	//Dentro deste bloco será realizado alguma gravação no banco de dados
	//-------------------------------------------------------------------

	Grava02()

	//-------------------------------------------------------------------
	//Bloco de Gravação D
	//Dentro deste bloco será realizado alguma gravação no banco de dados
	//-------------------------------------------------------------------

END TRANSACTION

Return 

Function Grava02()

BEGIN TRANSACTION

	//-------------------------------------------------------------------
	//Bloco de Gravação B
	//Dentro deste bloco será realizado alguma gravação no banco de dados
	//-------------------------------------------------------------------

	DisarmTransaction()

	Break

	//-------------------------------------------------------------------
	//Bloco de Gravação C
	//Dentro deste bloco será realizado alguma gravação no banco de dados
	//-------------------------------------------------------------------

END TRANSACTION

Return

No exemplo acima, a função Grava02 executou um DisarmTransaction após a sua gravação dos dados. Neste caso, os blocos “BLOCO A”, “BLOCO B”  e  “BLOCO D” não serão gravados no banco de dados, e o bloco  “BLOCO C” não será executado, pois, conforme veremos abaixo, após um DisarmTransaction só existem duas alternativas: Um Break, para que o fluxo seja desviado para depois do próximo comando END TRANSACTION ou a finalização da thread.

Caso uma transação seja iniciada com o sistema em TTSBREAK, o mesmo é abortado. 

Function Grava01()

BEGIN TRANSACTION

	//-------------------------------------------------------------------
	//Bloco de Gravação A
	//Dentro deste bloco será realizado alguma gravação no banco de dados
	//-------------------------------------------------------------------

	Grava02()


	BEGIN TRANSACTION
		
		//-------------------------------------------------------------------
		//Bloco de Gravação E
		//Dentro deste bloco será realizado alguma gravação no banco de dados
		//-------------------------------------------------------------------
	
	END TRANSACTION

END TRANSACTION

Return 

Function Grava02()

BEGIN TRANSACTION

	//-------------------------------------------------------------------
	//Bloco de Gravação B
	//Dentro deste bloco será realizado alguma gravação no banco de dados
	//-------------------------------------------------------------------

	DisarmTransaction()

	Break

	//-------------------------------------------------------------------
	//Bloco de Gravação C
	//Dentro deste bloco será realizado alguma gravação no banco de dados
	//-------------------------------------------------------------------

END TRANSACTION

Grava03()
 
Return
 
Function Grava03()
 
BEGIN TRANSACTION
 
	//-------------------------------------------------------------------
	//Bloco de Gravação D
	//Dentro deste bloco será realizado alguma gravação no banco de dados
	//-------------------------------------------------------------------
 
END TRANSACTION
 
Return

No exemplo acima, após sair da função Grava02() o sistema está em TTSBREAK,  e ao executar o comando BEGIN TRANSACTION  dentro  da função Grava03() o sistema será abortado por erro.

Atenção!

Após o DisarmTransaction, o sistema entra em TTSBREAK, e somente é possível iniciar uma nova transação depois que o fluxo de processamento passar por todos os comandos END TRANSACTION. Caso uma nova transação seja iniciada como sistema em TTSBREAK, a aplicação é finalizada pelo erro “Controle de transações: tentativa de abertura de transação pela rotina ROTINA após DisarmTransaction dos dados.”, sendo rotina a função que tentou executar o comando BEGIN TRANSACTION. Este comportamento se faz necessário para garantir a atomicidade da transação.

Controle de transações: como utilizar

A abertura de uma transação no Protheus deve ser realizada no momento de gravação dos dados, quando necessário.

A chamada da função DisarmTransaction() deve sempre ser seguida da finalização da thread  ou, quando necessário, de um BREAK, para que o fluxo da rotina seja direcionado para depois do END TRANSACTION . Esta função deve ser utilizada em casos específicos, não devendo ser utilizada de maneira indiscriminada no sistema, pois pode gerar erros de gravação ou interpretação errônea do fluxo do sistema.

Caso seja necessário é possível verificar, antes de abrir uma transação, se o sistema não está em TTSBREAK.


TTSBREAK

Em libs Protheus com versão acima da 08022017 é possível verificar se o sistema está em TTSBREAK  através da função FwInTTSBreak(). Esta função tem um retorno lógico, indicando se o sistema está ou não em TTSBREAK. Em um retorno positivo desta função um novo bloco de BEGIN TRANSACTION não pode ser chamado, pois o sistema ainda não executou todos os comandos de END TRANSACTIONS pendentes.

Em versões anteriores de lib. Protheus é necessário verificar a variável publica __TTSBreak (que indica se o sistema está em TTSBREAK) e se o sistema está em transação (através da função InTransact()).

Funções auxiliares

FwInTTSBreak

Retorna se o sistema está em TTSBREAK

Sintaxe: FWInTTSBreak() → Logical

Retorno: Logical → Indica se o sistema está em TTSBREAK.


InTransact

Retorna se o sistema está em transação

Sintaxe: InTransact() → Logical

Retorno: Logical → Indica se o sistema está em transação.


Para saber mais

BEGIN TRANSACTION

END TRANSACTION

Guia de boas Práticas - Transações

Status do documentoConcluído
Data
 
Versão1.0
Versão anterior1.0
Autores
Índice
  • Sem rótulos