Bloqueios de aplicação para uma operação de negócio
Coordene workers com sp_getapplock, trate os códigos de retorno e separe exclusão temporária de idempotência persistente.
Dois workers podem decidir que uma fatura está pronta antes de qualquer um registrar a conclusão. Uma restrição única pode proteger o número final sem coordenar todos os passos intermediários. Um bloqueio de aplicação oferece um recurso nomeado para sessões cooperantes do SQL Server serializarem essa operação de negócio.
Definir recurso e duração
Nomeie a menor unidade que precisa de exclusão, como invoice:481 em vez de all-invoices. Um nome global serializa clientes independentes sem necessidade. Nomes diferentes, por outro lado, criam bloqueios separados. Centralize a construção e inclua o identificador do tenant quando a numeração for única apenas dentro dele.
O recurso pertence a um banco e a um namespace de principal do banco. O mesmo texto em bancos distintos não cria exclusão compartilhada. Os nomes diferenciam maiúsculas de minúsculas. Use uma representação canônica e respeite o limite documentado de comprimento para evitar colisões por truncamento.
A propriedade transacional costuma ser clara para uma operação curta restrita ao banco. Commit ou rollback libera o bloqueio. A propriedade de sessão tem aplicações, mas exige considerar liberação explícita e reutilização de conexões. Uma conexão do pool não representa uma fronteira de negócio.
Conferir a aquisição
Execute o padrão em um banco de teste sem transação externa. Substitua o trecho indicado pela operação curta real. A verificação do código de retorno impede executar trabalho protegido depois de uma tentativa malsucedida.
IF @@TRANCOUNT <> 0
THROW 50000, 'This example owns its transaction.', 1;
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRAN;
DECLARE @rc int;
EXEC @rc = sys.sp_getapplock
@Resource = N'invoice:481',
@LockMode = 'Exclusive',
@LockOwner = 'Transaction',
@LockTimeout = 5000,
@DbPrincipal = 'public';
IF @rc < 0
THROW 50001, 'Application lock was not acquired.', 1;
-- Read durable operation record; perform short database work.
SELECT @rc AS LockResult;
COMMIT;
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 ROLLBACK;
THROW;
END CATCH;
Um código não negativo indica aquisição bem-sucedida. Um código negativo representa situações como timeout, cancelamento ou escolha como vítima de deadlock. O exemplo desfaz a transação para qualquer falha. Em produção, classifique os casos para registro e tentativas limitadas, mas nunca interprete falha como autorização para continuar.
Os cinco segundos limitam somente a aquisição desse bloqueio. Não limitam esperas posteriores por linhas, atrasos de rede ou a duração completa. Defina separadamente o orçamento da solicitação e garanta limpeza transacional após cancelamento.
Para testar, abra uma transação em A e adquira o recurso sem terminar. B deve atingir seu timeout. Desfaça A e repita B; agora a aquisição deve funcionar. Teste também recursos de faturas diferentes e confirme que avançam independentemente. Encerre explicitamente a transação deixada aberta no exercício.
Preservar garantias duráveis
Somente caminhos que adquirem o mesmo recurso seguem essa coordenação. Uma alteração administrativa direta ou uma versão antiga do aplicativo pode ignorar a convenção. Preserve restrições únicas, chaves estrangeiras e validações de transições permitidas. O bloqueio coordena participantes; não substitui o modelo de dados.
A liberação também não registra que a operação terminou. Se o cliente perder a resposta após o commit, uma nova tentativa pode adquirir o recurso novamente. Grave um identificador durável de operação e seu resultado na mesma transação da mudança de negócio. Sob o bloqueio, consulte esse registro primeiro e devolva o resultado existente para solicitações duplicadas.
Não mantenha a transação aberta durante uma chamada a um serviço de pagamento. Um rollback SQL não desfaz uma cobrança externa concluída. Grave um item de outbox atomicamente e processe a entrega por um caminho idempotente. Caso uma transação precise de vários recursos, adquira-os sempre na mesma ordem: bloqueios de aplicação também podem participar de deadlocks. Meça falhas de aquisição, tempo de espera e idade transacional para confirmar que somente o trabalho da mesma chave disputa exclusão, enquanto operações independentes continuam concorrentes.
Referências técnicas: Microsoft Learn: sp_getapplock · Microsoft Learn: sp_releaseapplock.