As funções RecLock, SoftLock e SimpleLock em ADVPL controlam concorrência no Protheus.
RecLock bloqueia registros para inclusão/alteração, exigindo MSUnlock para liberar.
SoftLock bloqueia registros durante operações de interface, sem obrigar atualização imediata, necessitando liberação manual.
SimpleLock é usada em processos pesados, pula registros bloqueados, melhorando desempenho, e também requer liberação via MSRUnlock.
Tempo aproximado para leitura: 00:02:00 min
Dúvida
Quais são as diferenças e os cenários de aplicação adequados para as funções de controle de concorrência RecLock, SoftLock e SimpleLock em customizações e desenvolvimentos ADVPL?
Ambiente
Cross Segmento - TOTVS Backoffice (Linha Protheus) – ADVPL – A partir da versão 12.
Solução
O controle de concorrência é um método usado para garantir que as transações sejam executadas de forma segura e que sigam as regras de Atomicidade, Consistência, Isolamento e Durabilidade. No Protheus, existem padrões para operações de concorrência que visam reduzir ocorrências de serialização e otimizar o desempenho do sistema.
Abaixo estão detalhadas as diferenças e aplicações das três funções de bloqueio abordadas:
RecLock
Função utilizada para iniciar a inclusão ou alteração de um registro no Alias informado.
Quando utilizada para inclusão, o novo registro permanece apenas na memória do Servidor de Aplicação até o momento em que uma operação de reposicionamento de registro ou de confirmação ocorra.
O registro é mantido bloqueado em modo exclusivo para o processo que está realizando a operação.
O Framework realiza o bloqueio e atualiza a leitura do registro corrente da tabela.
A função RecLock() deve obrigatoriamente trabalhar em conjunto com a função MSUnlock(), que efetiva e finaliza a operação.
Observação: É importante que o alias que sofrerá o lock não pode ser uma Query ou estar aberto em modo "somente leitura", pois, nestes casos, as operações de inclusão ou alteração não serão possíveis.
Exemplo de código de inclusão (.T.) com o RecLock:
DbSelectArea("SA1")
RecLock("SA1", .T.)
SA1->A1_FILIAL := xFilial("SA1")
SA1->A1_COD := "900001"
SA1->A1_LOJA := "01"
MsUnLock()
Exemplo de código de alteração (.F.) com o RecLock:
DbSelectArea("SA1")
DbSetOrder(1)
If DbSeek("01"+"900001"+"01")
RecLock("SA1", .F.)
SA1->A1_NOME := "CLIENTE TESTE"
SA1->A1_NREDUZ := "TESTE"
MsUnLock() // Confirma e finaliza a operação
EndIf
SoftLock
Esta função deve ser utilizada para bloquear um determinado registro, em atualização, durante as operações de interface (como Browses).
Ela difere da função RecLock() pois não gera uma obrigação imediata de atualização no banco de dados.
O SoftLock garante que a interface somente seja montada para o primeiro usuário que fez a tentativa de atualização ou exclusão.
Enquanto a transação não for abortada ou concluída, o registro permanecerá bloqueado para os demais.
Após o uso da função SoftLock, realizar o uso da função RecLock continua a ser necessário na transação para a efetiva gravação dos dados.
Exemplo de código com a SoftLock:
LOCAL lConfirma := .F.
dbSelectArea("SA1")
dbSetOrder(1) // A1_FILIAL + A1_COD + A1_LOJA
dbSeek(xFilial("SA1") + "900001" + "01") // Busca exata
IF FOUND() // Avalia o retorno da pesquisa realizada
SOFTLOCK() // Reserva o registro localizado
// Função ilustrativa que exibe os dados do registro posicionado e permite a alteração dos mesmos.
lConfirma := AlteraSA1()
IF lConfirma
RECLOCK("SA1", .F.)
SA1->A1_NOME := "MARCOS AURELIUS TERCEIRUS"
SA1->A1_NREDUZ := "MARCOS AURELIUS"
MSUNLOCK() // Destrava o registro, liberando o RECLOCK() e o SOFTLOCK() do registro
ENDIF
ENDIFObservação: Vale destacar de forma mais contundente que, após um SoftLock(), o registro deve ser liberado manualmente pela própria rotina que gerou o lock. Isso ocorre porque ele não passa pelo controle de transações do ERP e não é alcançado pelas rotinas padrões de liberação de registros.
SimpleLock
Função indispensável em rotinas de processamento pesado (lote) para trazer benefícios de desempenho e evitar a paralisação do sistema.
Esta função avalia se o registro pode ser bloqueado e caso não consiga, a rotina passará para o próximo registro e assim sucessivamente até o termino do processamento.
A grande vantagem do seu uso é que, quanto mais chamadas o cliente fizer da mesma rotina concorrentemente, mais rápido será o processamento geral da rotina, pois os registros travados são pulados.
A rotina que realizou o bloqueio do registro via SimpleLock é responsável por realizar a liberação do mesmo, através da MsrUnlock.
A função SimpleLock não participa do controle de transações padrão do sistema e nem sofre desbloqueio através do comando MsUnlockAll.
Exemplo de código com a SimpleLock:
#INCLUDE "TOTVS.CH"
User Function ExSimpleL()
Local cCodProd := Padr("TESTE01", TamSx3("B1_COD")[1])
Local nTentativas := 0
Local nMaxTentativas := 10
Local lBloqueado := .F.
// 1. Posicionamento na tabela desejada
DbSelectArea("SB1")
SB1->(DbSetOrder(1)) // Filial + Codigo
If SB1->(DbSeek(xFilial("SB1") + cCodProd))
// 2. Controle de concorrência amigável
// Tenta bloquear o registro; se falhar, aguarda e tenta novamente
While !(lBloqueado := SimpleLock()) .And. nTentativas < nMaxTentativas
nTentativas++
Sleep(2000) // Aguarda 2 segundos
EndDo
If lBloqueado
// 3. Efetivação da gravação
// O registro está reservado para esta thread, podemos gravar com segurança
RecLock("SB1", .F.)
SB1->B1_DESC := "TESTE SIMPLELOCK - " + Time()
MsUnLock() // Confirma a alteração (libera o RecLock, mas não o SimpleLock)
// 4. Liberação OBRIGATÓRIA do SimpleLock
MsRUnlock(SB1->(RecNo()))
ConOut("Sucesso: Produto atualizado e lock liberado.")
Else
ConOut("Timeout: O registro permaneceu bloqueado por outra thread.")
EndIf
Else
ConOut("Aviso: Produto não localizado na SB1.")
EndIf
Return
Observação: Para um controle de forma "amigável" a função SimpleLock() pode ser utilizado, pois pode tentar travar o registro para alteração e, caso já esteja em uso, abortar aguardando a liberação, sendo que retorna .T., se realizou o bloqueio do registro e .F. não conseguiu realizar o bloqueio.
Saiba mais
Reclock
Softlock
Simplelock
Guia de boas práticas - Transações
MSUnlock()
Alterar TIMEOUT: RecLock e SoftLock
0 Comentários