Ao implementar o procedimento de semaforos em nossos sistemas nos deparamos sempre com o seguinte problema:
Se um registro for travado em uma estação, outra estação não poderá ter acesso a alteração do mesmo. Então implementamos a seguinte mensagem. registro travado em outra estação.
Poxa, mas se ta travado não posso fazer nada?
Posso sim, Visualiza-lo.
Mas como visualizar sem causar algum tipo de problema no mesmo.
Como sabemos a função RLock() ou dbRlock() é uma faca de dois legumes. Se numa rede duas maquinas tentam ao mesmo tempo travar um registro no final o que teremos é um registro destravado, pois num milésimo de segundo o registro foi travado e no outro destravado.
Então a solução, sempre será o uso de semáforos e cada um implementa da forma mais coerente e funcional.
Estes problemas de travamento não é só dos RDDs NTX/CDX e acontecem também no MySQL( já tive relatos de dificuldades neste sentido ).
No meu caso, a idéia não seria apresentar uma mensagem ao usuário e fechar, mas sim permitir ao usuário ainda visualizar o registro sem permitir alterações.
Todas as minhas tabelas possuem um campo identificador unico que chamo de IDESTACAO mas voce pode criar o seu a seu gosto.
Em Fivewin ou outra GUI esta técnica seria possivel seguinte o exemplo abaixo:
SELE CLIENTES
...
lSemaforo := .f.
if CLIENTES->IDESTACAO = 0
// SEMAFORO LIGADO
CLIENTES->( dbRLock() )
CLIENTES->IDESTACAO := user_id // Travo o registro, salvo o IDentificador do usuario e libero o registro
CLIENTES->( dbUnlock() )
CLIENTES->( dbCommit() )
else
lSemaforo := .t.
//Isto eu nao quero
//MsgRun( "Registro "+alltrim(str(CLIENTES->IDCLIENTE))+" sendo atualizacao em outra estacao!" )
//return .t.
endif
...
// Carregos os campos em variaveis e faço a alteração ou visualizao
O pulo do gato ficaria por conta da propria interface:
...
ACTIVATE DIALOG oDialog ON INIT iif( lSemaforo, oButton:Disable(), oButton:Enable() )
...
Então o codigo de fechamento ficaria assim:
...
REDEFINE BUTTON oButton ID 100 OF oDialog PROMPT "Confirma e fecha." ACTION ( lSave := .t. , oDialog:End() )
...
ACTIVATE DIALOG oDialog ON INIT iif( lSemaforo, oButton:Disable(), oButton:Enable() )
if lSave
// Salvar o Registro
...
else
GO nRegClient
if CLIENTES->IDESTACAO # 0 // Se o registro foi marcado
if CLIENTES->IDESTACAO = user_id // Se o usuario e o mesmo que marcou
// MsgRun( "Liberando o registro" )
// SEMAFORO LIGADO
CLIENTES->( dbRLock() )
CLIENTES->IDESTACAO := 0
CLIENTES->( dbUnlock() )
CLIENTES->( dbCommit() )
endif
endif
endif