sql >> Base de Datos >  >> RDS >> Sqlserver

Violación de la restricción CLAVE ÚNICA en INSERTAR DONDE CONTAR(*) =0 en SQL Server 2005

¿Por qué no funciona esto?

Creo que el comportamiento predeterminado de SQL Server es liberar bloqueos compartidos tan pronto como ya no sean necesarios. Su subconsulta dará como resultado un bloqueo compartido (S) de corta duración en la tabla, que se liberará tan pronto como se complete la subconsulta.

En este punto, no hay nada que impida que una transacción simultánea inserte la misma fila que acaba de verificar que no estaba presente.

¿Qué modificación debo hacer para que no haya posibilidad de una excepción debido a la violación de la restricción?

Agregando el HOLDLOCK la sugerencia a su subconsulta le indicará a SQL Server que retenga el bloqueo hasta que se complete la transacción. (En su caso, esta es una transacción implícita). El HOLDLOCK sugerencia es equivalente a SERIALIZABLE sugerencia, que en sí misma es equivalente al nivel de aislamiento de transacción serializable al que hace referencia en su lista de "otros enfoques".

El HOLDLOCK solo la sugerencia sería suficiente para retener el bloqueo S y evitar que una transacción simultánea inserte la fila contra la que está protegiéndose. Sin embargo, es probable que su error de violación de clave única sea reemplazado por interbloqueos, que ocurren con la misma frecuencia.

Si solo retiene un bloqueo S en la mesa, considere una carrera entre dos intentos simultáneos para insertar la misma fila, procediendo al mismo paso:ambos logran adquirir un bloqueo S en la mesa, pero ninguno puede tener éxito en adquirir el Exclusivo Bloqueo (X) necesario para ejecutar la inserción.

Afortunadamente, hay otro tipo de bloqueo para este escenario exacto, llamado bloqueo de actualización (U). El bloqueo U es idéntico a un bloqueo S con la siguiente diferencia:mientras que varios bloqueos S se pueden mantener simultáneamente en el mismo recurso, solo se puede mantener un bloqueo U a la vez. (Dicho de otra manera, mientras que los bloqueos S son compatibles entre sí (es decir, pueden coexistir sin conflicto), los bloqueos U no son compatibles entre sí, pero pueden coexistir junto con los bloqueos S; y más adelante en el espectro, los bloqueos exclusivos (X) no son compatibles. compatible con candados S o U)

Puede actualizar el bloqueo S implícito en su subconsulta a un bloqueo U usando UPDLOCK pista.

Ahora se serializarán dos intentos simultáneos de insertar la misma fila en la tabla en la declaración de selección inicial, ya que esto adquiere (y retiene) un bloqueo U, que no es compatible con otro bloqueo U del intento de inserción concurrente.

Valores NULOS

Un problema aparte puede surgir del hecho de que FieldC permite valores NULL.

Si ANSI_NULLS está activado (predeterminado) entonces la verificación de igualdad FieldC=NULL devolvería falso, incluso en el caso de que FieldC sea NULL (debe usar IS NULL operador para verificar nulo cuando ANSI_NULLS Está encendido). Dado que FieldC es anulable, su verificación de duplicados no funcionará al insertar un valor NULL.

Para manejar correctamente los nulos, deberá modificar su subconsulta EXISTS para usar IS NULL operador en lugar de = cuando se inserta un valor de NULL. (O puede cambiar la tabla para no permitir valores NULL en todas las columnas correspondientes).

Referencias de libros en línea de SQL Server

  • Sugerencias de bloqueo
  • Matriz de compatibilidad de bloqueo
  • ANSI_NULLS