Tengo un procedimiento almacenado que básicamente selecciona valores de una tabla y los inserta en otra, una especie de archivo. Quiero evitar que varias personas hagan eso al mismo tiempo.
Mientras se ejecuta este procedimiento, no quiero que nadie más pueda iniciarlo; sin embargo, no quiero la serialización, la otra persona ejecutará el procedimiento una vez que haya terminado con él.
Lo que quiero es que la otra persona que intenta iniciarlo obtenga un error, mientras estoy ejecutando el procedimiento.
He intentado usar sp_getapplock, sin embargo, no puedo detener por completo a la persona para que no ejecute el procedimiento.
También intenté encontrar el procedimiento con sys.dm_exec_requests y bloquear el procedimiento, aunque esto funciona, creo que no es óptimo porque en algunos servidores no tengo los permisos para ejecutar sys.dm_exec_sql_text (sql_handle).
¿Cuál es la mejor manera de hacer esto?
fuente
Respuestas:
Para agregar a la respuesta de @ Tibor-Karaszi, establecer un tiempo de espera de bloqueo en realidad no produce un error (he enviado un RP contra los documentos). sp_getapplock solo devuelve -1, por lo que debe verificar el valor de retorno. Así como esto:
fuente
Use sp_getapplock al comienzo del proceso y establezca un tiempo de espera de bloqueo en un valor muy bajo. De esta forma, obtienes un error cuando estás bloqueado.
fuente
Otra opción es construir una tabla para controlar el acceso al procedimiento. El siguiente ejemplo muestra una posible tabla, así como un procedimiento que podría utilizarla.
fuente
IsLocked
estado a 0 en ese caso? También tengo curiosidad sobre su uso deCOALESCE
aquí. Puede@@ROWCOUNT
ser nulo después de declaraciones comoUPDATE
? Finalmente, solo un pequeño detalle, ¿por qué poner un punto y coma delante de laTHROW
declaración en ese caso específico?Creo que estás tratando de resolver el problema de manera incorrecta. Lo que desea es la máxima protección de la coherencia de la base de datos. Si dos personas ejecutan un procedimiento almacenado al mismo tiempo, se puede violar la coherencia de la base de datos.
Para protegerse contra varios tipos de inconsistencias de la base de datos, el estándar SQL tiene cuatro niveles de aislamiento de transacciones:
Sin embargo, el estándar SQL tiene un enfoque basado en el bloqueo para estas inconsistencias de la base de datos, y por razones de rendimiento, muchas bases de datos adoptan un enfoque basado en el aislamiento de instantáneas que básicamente tiene estos niveles:
Las cancelaciones de transacciones en estas bases de datos basadas en el aislamiento de instantáneas pueden parecer preocupantes, pero una vez más, cada base de datos cancelará una transacción debido a un punto muerto, por lo que cualquier aplicación razonable necesita de todos modos poder volver a intentar una transacción.
Lo que desea es el nivel de aislamiento SERIALIZABLE : asegura que si las transacciones ejecutadas independientemente una tras otra dan como resultado un buen estado, cualquier ejecución paralela de las transacciones también resulta en un buen estado. Afortunadamente, Michael Cahill descubrió en su disertación doctoral cómo el nivel de aislamiento SERIALIZABLE puede ser soportado por bases de datos aisladas instantáneas con poco esfuerzo.
Si utiliza un nivel de aislamiento SERIALIZABLE en una base de datos aislada de instantánea, si dos personas intentan ejecutar el procedimiento almacenado al mismo tiempo y se pisarían los pies, la transacción se cancelaría.
Ahora, ¿SQL Server admite realmente el nivel de aislamiento SERIALIZABLE (en lugar de enmascarar el aislamiento de la instantánea detrás de la palabra clave SERIALIZABLE )? Francamente, no lo sé: la única base de datos que sé que lo admite es PostgreSQL.
Aunque no pude dar consejos específicos de SQL Server, todavía estoy publicando esta respuesta, ya que los usuarios de PostgreSQL y los usuarios de otras bases de datos que pueden considerar cambiar a PostgreSQL pueden beneficiarse de mi respuesta. Además, los usuarios de bases de datos que no son de PostgreSQL que no pueden cambiar a PostgreSQL pueden presionar a su proveedor de bases de datos favorito para que ofrezca un nivel de aislamiento SERIALIZABLE genuino .
fuente
Me doy cuenta de que el problema "real" puede ser más complejo.
En caso de que no lo sea: si archiva con desencadenadores de inserción y / o actualización, puede evitar el problema que está tratando de resolver.
Espero que ayude,
-Chris C.
fuente
the 'real' problem may be more complex
. En caso de que no lo sea, los desencadenantes son una buena solución. Además, probablemente será más fácil de probar y mantener porque es una característica de la base de datos en lugar de una solución personalizada.