As transações tendem a serializar o sistema e deixá-lo mais lento em ambientes multiusuário. Para mitigar a serialização são necessários alguns cuidados.

O primeiro cuidado a se tomar, é evitar um DeadLock. Um sistema está em estado de DeadLock quando existe uma operação (A) fazendo um bloqueio em um registro (L1) e tentando bloquear outro registro (L2) da mesma tabela. Neste mesmo momento existe outra operação (B) bloqueando o registro (L2) e tentando bloquear o registro (L1). Nesta situação não existe como o banco resolver as solicitações, então ele elege, aleatoriamente, uma das conexões e a encerra provocando um erro para o usuário.

   

 

Existem duas maneira de resolver um DeadLock. A primeira é garantir que a transação não bloqueie mais de um registro da mesma tabela. Isto pode ser feito reduzindo o tamanho da transação,  de modo a garantir e manter a integridade do sistema.

Exemplo: Ao gravar um formulário do tipo Master/Detail pode-se fazer uma transação para o Master e primeiro registro Detail e outra para os demais itens.

 

// DeadlockPreventionSample.prw

For nX := 1 To Len(aItens)

       Begin Transaction

             If nX == 1

                    RecLock("SC5", .T.)

             EndIf

             RecLock("SC6",.T.)

             MaAvalSc6()

       End Transaction Lockin "SC5"

Next nX

 

Begin Transaction

       RecLock("SC5")

       MaAvalSc5()

End Transaction

 

Note que durante todo o processo, a tabela SC5 está bloqueada e somente é liberada na última transação. Isto é garantido pelo comando End Transaction Lockin "SC5", que atualiza a transação, mas mantém o bloqueio do registro para não gerar problemas em outros processamentos concorrentes, conforme informado anteriormente.

Porém, este método como pode ser visto, não garante a total Consistência (aCid) dos dados, uma vez que em caso de queda, a transação apesar de integra, não contém todos os dados informados pelo usuário ou processo. 

 

Outra maneira de resolver é manter o mesmo ordenamento (sequenciamento de registros) durante os locks. Porém, esta implementação deve garantir que em todo o sistema, seja utilizada a mesma lógica para o lock desta tabela.

 

A escolha de um dos métodos vai depender do tipo da transação.

 

Transações de formulário devem, obrigatoriamente, seguir o  primeiro exemplo. As transações são mais rápidas e o risco é a atualização parcial do formulário digitado, porém ele estará íntegro. Com certeza o usuário final prefere perder alguns dados a tudo.

Porém existirão casos em que a atualização parcial não fornece uma transação íntegra. Para estes casos, deve-se  utilizar o segundo método. Um bom exemplo são as notas fiscais, em que em caso de queda,  o usuário tende a cancelar a nota e refazê-la se houver falta de itens, ou seja, o modelo anterior não traz benefícios ao usuário. Neste exemplo, a ordenação da transação deveria ser por produto+local, visto que a tabela SB2 é atualizada.

 

É importante destacar que durante uma transação não é possível liberar um lock, em nenhuma hipótese. Os locks somente são liberados após o encerramento da transação, sem nenhum controle do desenvolvedor.

 

 

  • Sem rótulos