Tenho um módulo IIS que atende a várias requisições ao mesmo tempo. Na entrada de cada requisição, quero registrar a última vez que o serviço foi acessado:
update log set last_access = getdate()
Mas com o nível de simultaneidade que às vezes consigo ter, tenho medo de facilmente ter conflitos.
Como meu log não precisa de uma precisão de milissegundos (ele será consultado para verificar se o servidor foi acessado nos últimos X minutos, não milissegundos), então, se meu log enfrentar um conflito, ele pode perfeitamente ignorar esse log e simplesmente não fazer nada.
Minha ideia inicial era proteger meu registro dentro de um bloco try-catch e simplesmente ignorar os conflitos.
begin try
update log set last_access = getdate()
end try
begin catch
-- We do nothing and ignore that another request has logged an access at the same time
end catch
Mas isso está correto?. Em caso de conflito, pularei automaticamente para a seção catch, não faça nada, para que meu Backend possa continuar atendendo normalmente o restante da requisição?.
Receio que ele possa esperar o deadlock ser liberado e continuar após um timeout. Existe uma maneira melhor de atualizar um valor, enquanto diz ao SQL Server para simplesmente ignorar essa atualização se outra sessão já tiver feito isso ao mesmo tempo?
PS: este log de atualização será executado em sua própria transação, enquanto qualquer operação SQL necessária para atender à solicitação será executada em transações separadas.
Obrigado.
Considerando essas duas coisas juntas, acredito que você esteja pensando demais e não precisa se preocupar com isso.
É realmente possível obter uma situação de simultaneidade ou condição de corrida tal que um acesso posterior pode conseguir empurrar sua atualização antes do acesso anterior. No entanto, estamos falando de no máximo alguns milissegundos aqui de uma forma ou de outra. Como esse nível de precisão não importa, você ficará bem.
A outra preocupação é o bloqueio ou travamento causado por várias atualizações ao mesmo tempo. Mas, novamente, parece que você está pensando demais nisso. Bancos de dados relacionais geralmente são bons em lidar com essa situação dentro do banco de dados. Eles bloquearão apropriadamente para garantir que ambas as atualizações aconteçam, e de forma atômica e performática, onde a atualização posterior vence para definir o valor final para uma determinada linha/coluna. Esse tipo de coisa é uma das grandes razões pelas quais os bancos de dados relacionais foram criados em primeiro lugar.
É possível criar deadlocks, onde, por exemplo, a transação A está esperando um bloqueio da transação B que está esperando um bloqueio da transação A, e eles ficam presos para sempre. Cadeias/anéis mais longos e complicados também são possíveis. Mas isso geralmente envolve transações que bloqueiam mais de uma coisa, e em ordens diferentes. Isso não está acontecendo aqui.
A única coisa que eu poderia fazer é garantir que você tenha uma
WHERE
cláusula, mesmo que haja apenas uma linha na tabela.Olhando para os comentários postados desde que comecei a escrever a resposta original, vejo que várias linhas estão em jogo, afinal. Isso cria um (pequeno!) potencial para deadlocks. Há quatro coisas que você pode fazer para ajudar. Escolha QUALQUER UMA delas e isso garantirá que você evite deadlocks, desde que seja feito de forma consistente.
getdate()
valor,