Eu tenho um procedimento armazenado que basicamente seleciona valores de uma tabela e os insere em outra, uma espécie de arquivamento. Quero evitar que várias pessoas façam isso ao mesmo tempo.
Enquanto esse procedimento estiver em execução, não quero que mais ninguém possa iniciá-lo; no entanto, não quero a serialização, a outra pessoa executará o procedimento após o término.
O que eu quero é que a outra pessoa que esteja tentando iniciá-lo receba um erro enquanto estou executando o procedimento.
Eu tentei usar sp_getapplock, no entanto, não consigo parar completamente a pessoa de executar o procedimento.
Eu também tentei encontrar o procedimento com sys.dm_exec_requests e bloquear o procedimento, enquanto isso funciona, acho que não é o ideal, porque em alguns servidores não tenho permissões para executar o sys.dm_exec_sql_text (sql_handle).
Qual é a melhor maneira de fazer isso?
fonte
Respostas:
Para adicionar à resposta de @ Tibor-Karaszi, definir um tempo limite de bloqueio não produz um erro (enviei um PR contra os documentos). sp_getapplock apenas retorna -1, então você deve verificar o valor de retorno. Então assim:
fonte
Use sp_getapplock no início do processo e defina um tempo limite de bloqueio para um valor muito baixo. Dessa forma, você recebe um erro quando está bloqueado.
fonte
Outra opção é criar uma tabela para controlar o acesso ao procedimento. o exemplo abaixo mostra uma tabela possível e um procedimento que pode ser usado.
fonte
IsLocked
estado para 0 nesse caso? Também estou curioso sobre o seu usoCOALESCE
aqui. Pode@@ROWCOUNT
ser nulo após declarações comoUPDATE
? Por fim, apenas um pequeno detalhe, por que colocar um ponto-e-vírgula na frente daTHROW
declaração nesse caso específico?Eu acho que você está tentando resolver o problema de maneira incorreta. O que você deseja é a máxima proteção da consistência do banco de dados. Se duas pessoas executam um procedimento armazenado ao mesmo tempo, a consistência do banco de dados pode ser violada.
Para proteger contra vários tipos de inconsistências do banco de dados, o padrão SQL possui quatro níveis de isolamento de transação:
No entanto, o padrão SQL possui uma abordagem baseada em bloqueio para essas inconsistências do banco de dados e, por razões de desempenho, muitos bancos de dados adotam uma abordagem baseada em isolamento de instantâneo que basicamente possui esses níveis:
Os cancelamentos de transação nesses bancos de dados baseados em isolamento de captura instantânea podem parecer preocupantes, mas, novamente, todos os bancos de dados cancelam uma transação devido a um conflito, portanto, qualquer aplicativo razoável precisa, de qualquer maneira, poder tentar novamente uma transação.
O que você deseja é o nível de isolamento SERIALIZABLE : garante que se as transações executadas independentemente uma após a outra resultem em um bom estado, qualquer execução paralela das transações também resultará em um bom estado. Felizmente, Michael Cahill, em sua tese de doutorado, descobriu como o nível de isolamento SERIALIZABLE pode ser suportado por bancos de dados isolados de captura instantânea com pouco esforço.
Se estiver usando um nível de isolamento SERIALIZABLE em um banco de dados isolado de captura instantânea, se duas pessoas tentarem executar o procedimento armazenado simultaneamente e pisarem nos dedos uma da outra, uma das transações será cancelada.
Agora, o SQL Server oferece suporte genuíno ao nível de isolamento SERIALIZABLE (em vez de mascarar o isolamento de instantâneo atrás da palavra-chave SERIALIZABLE )? Francamente, não sei: o único banco de dados que conheço que o suporta é o PostgreSQL.
Mesmo que eu não tenha dado conselhos específicos ao SQL Server, continuo postando essa resposta, pois usuários do PostgreSQL e usuários de outros bancos de dados que podem considerar a possibilidade de mudar para o PostgreSQL podem se beneficiar da minha resposta. Além disso, os usuários de bancos de dados não PostgreSQL que não podem mudar para o PostgreSQL podem pressionar seu fornecedor de banco de dados favorito para oferecer um nível de isolamento SERIALIZABLE genuíno .
fonte
Sei que o problema "real" pode ser mais complexo.
Caso contrário, se você arquivar com gatilhos de inserção e / ou atualização, poderá evitar o problema que está tentando resolver.
Espero que ajude,
-Chris C.
fonte
the 'real' problem may be more complex
. Caso isso não aconteça, os gatilhos são uma boa solução. Além disso, provavelmente será mais fácil testar e manter, porque é um recurso do banco de dados, e não uma solução personalizada.