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). 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 CLOSETRANSACTION LOCKIN, que atualiza a transação, mas mantém o bloqueio do registro para não gerar problemas em outros processamentos concorrentes, conforme informado anteriormente.
Outra maneira de resolver, é utilizando a função MultLock. Esta função garante o bloqueio de todos os registros de uma mesma tabela. A sua desvantagem é o aumento da serialização do produto. Por este motivo, deve-se utilizá-la com muito cuidado e ter em mente que sempre há uma alternativa para evitar-se o seu uso.
// MultlockSample.prw
If MultLock("SB2",aMults,1)
Begin Transaction
// Faz alguma coisa
End Transaction
EndIf
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 “MultLock”. 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.