Bloqueos de aplicación para una operación de negocio
Coordine trabajadores con sp_getapplock, interprete sus códigos de retorno y diferencie exclusión temporal de idempotencia duradera.
Dos trabajadores pueden decidir que una factura está lista antes de que cualquiera registre su finalización. Una restricción única puede proteger el número definitivo sin coordinar todos los pasos intermedios. Un bloqueo de aplicación proporciona un recurso con nombre para que sesiones cooperantes de SQL Server serialicen esa operación concreta.
Definir recurso y duración
Nombre la unidad mínima que requiere exclusión, por ejemplo invoice:481 en lugar de all-invoices. Un nombre global serializa clientes independientes innecesariamente. Nombres diferentes, por otro lado, crean bloqueos independientes. Centralice la construcción e incluya el identificador del cliente cuando la numeración solo sea única dentro de ese ámbito.
El recurso pertenece a una base y a un espacio de nombres de principal de base. El mismo texto en bases distintas no produce exclusión compartida. Los nombres distinguen mayúsculas de minúsculas. Utilice una representación canónica y respete la longitud documentada para evitar colisiones por truncamiento.
La propiedad transaccional suele ser sencilla para una operación breve exclusivamente de base de datos. Commit o rollback libera el bloqueo. La propiedad de sesión tiene usos, pero obliga a razonar sobre liberación explícita y reutilización de conexiones. Una conexión del pool no constituye una frontera de operación de negocio.
Comprobar la adquisición
Ejecute el patrón en una base de pruebas sin transacción exterior. Sustituya la ubicación marcada por el trabajo breve real. La comprobación del código de retorno evita continuar con la sección protegida cuando la adquisición falla.
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;
Un código no negativo indica éxito. Un código negativo identifica situaciones como timeout, cancelación o selección como víctima de interbloqueo. El ejemplo revierte ante cualquier fallo. En producción puede clasificar errores para registro y reintentos limitados, pero nunca debe interpretarlos como autorización para continuar.
Los cinco segundos limitan únicamente la adquisición del bloqueo de aplicación. No limitan esperas posteriores por filas, retrasos de red ni la duración completa. Defina por separado el presupuesto de la solicitud y garantice limpieza transaccional después de una cancelación.
Para probar la exclusión, abra una transacción en A y adquiera el recurso sin terminar. B debe agotar su espera. Revierta A y repita B; ahora debería adquirirlo. Pruebe también recursos de facturas diferentes y confirme que avanzan de forma independiente. Cierre explícitamente la transacción de demostración.
Mantener garantías persistentes
Solo quedan coordinadas las rutas que adquieren el mismo recurso. Un cambio administrativo directo o una versión antigua de la aplicación puede ignorar el acuerdo. Mantenga restricciones únicas, claves externas y validaciones de transiciones de estado. El bloqueo coordina participantes; no sustituye el modelo de datos.
Además, liberar el recurso no conserva memoria de una finalización. Si el cliente pierde la respuesta después del commit, un reintento puede adquirirlo otra vez. Almacene un identificador de operación y su resultado junto con el cambio de negocio. Dentro del bloqueo, busque primero ese registro y devuelva el resultado anterior cuando la solicitud esté repetida.
No mantenga abierta la transacción mientras llama a un servicio de pagos. El rollback no revierte un cargo externo exitoso. Registre un elemento de outbox atómicamente y entréguelo mediante un proceso idempotente. Si necesita varios recursos, adquiéralos siempre en el mismo orden: los bloqueos de aplicación también participan en interbloqueos. Mida fallos, duración de espera y edad transaccional para demostrar que compite solamente el trabajo sobre la misma clave, mientras las operaciones independientes conservan su concurrencia.
Referencias técnicas: Microsoft Learn: sp_getapplock · Microsoft Learn: sp_releaseapplock.