2009-06-15 25 views
6

estoy actualmente insertar un registro en una tabla de SQL Server y luego seleccionar la ID de incremento automático de la siguiente manera:¿Por qué el siguiente SQL Server inserta interbloqueo cuando se ejecuta dentro de una transacción?

(@p0 int,@p1 nvarchar(8))INSERT INTO [dbo].[Tag]([Some_Int], [Tag]) 
VALUES (@p0, @p1) 

SELECT CONVERT(Int,SCOPE_IDENTITY()) AS [value] 

(Esto se ha generado utilizando LINQ to SQL). Por alguna razón, cuando ejecuto este código dentro de una transacción utilizando el objeto TransactionScope con un nivel de aislamiento Serializable, SQL Server arroja un error de interbloqueo. Analicé los acontecimientos gráfico de interbloqueo y se encontró que los dos procesos implicados fueron cada espera en el otro para realizar la operación de conversión, como entiendo la siguiente información:

<resource-list> 
    <keylock hobtid="72057594101170176" dbid="5" objectname="foo.dbo.Tag" indexname="PK_Tag_1" id="lockb77cdc0" mode="RangeS-S" associatedObjectId="72057594101170176"> 
    <owner-list> 
    <owner id="processc9be40" mode="RangeS-S"/> 
    </owner-list> 
    <waiter-list> 
    <waiter id="processc9ae38" mode="RangeI-N" requestType="convert"/> 
    </waiter-list> 
    </keylock> 
    <keylock hobtid="72057594101170176" dbid="5" objectname="foo.dbo.Tag" indexname="PK_Tag_1" id="lockb77cdc0" mode="RangeS-S" associatedObjectId="72057594101170176"> 
    <owner-list> 
    <owner id="processc9ae38" mode="RangeS-S"/> 
    </owner-list> 
    <waiter-list> 
    <waiter id="processc9be40" mode="RangeI-N" requestType="convert"/> 
    </waiter-list> 
    </keylock> 
    </resource-list> 

Mi comprensión era que el ámbito de transacción impediría la segunda proceso de realizar la inserción hasta que el primero haya terminado tanto insertando como seleccionando la identidad. Sin embargo, este no parece ser el caso. ¿Alguien podría arrojar algo de luz sobre el mejor enfoque para lograr lo que necesito de una manera segura?

- Actualizado -

para notar; Estoy 99% seguro de que una conexión no se comparte entre los dos procesos, ya que cada uno crea un nuevo DataContext para comunicarse con la base de datos.

- actualizado de nuevo -

Remus Ruşanu señaló que algunos información omitida se relaciona con el problema, he tratado de simplificar el escenario basado en el informe gráfico de interbloqueo, pero he ampliado la explicación aquí. Antes de hacer la inserción, realizo una consulta existente en la tabla en cuestión para determinar si la etiqueta ya existe. Si lo hace, termino la transacción. Si no, la inserción debe continuar y luego realizar una actualización, que no se muestra aquí, en una tabla que tiene Some_Int como la clave principal, aunque la actualización es puramente para un último valor modificado. También puede ser importante que la tabla de etiquetas tenga un índice agrupado compuesto por ID de auto inc y Some_Int. No creo que esta última información sea relevante, ya que he intentado cambiar la tabla para que el campo autoinc sea la clave principal/índice agrupado en vano.

Gracias.

+0

Maldita buena pregunta! Quiero ver una respuesta. – Chris

Respuesta

7

La 'conversión' en cuestión es un 'lock convert' from RangeS-S to RangeI-N, no relacionado con la función 'CONVERTIR' de ninguna manera. El hecho de que tenga bloqueos RangeS-S ya colocados en el índice PK_Tag_1 indica que está haciendo algo más que solo un INSERTAR. ¿Su transacción hace, por casualidad, un cheque primero para ver si el nuevo registro 'existe' antes de intentar la inserción?

+0

de hecho lo hace ... – LaserJesus

+0

He actualizado la pregunta para reflejar la situación más completamente – LaserJesus

+0

Cambié el nivel de aislamiento a instantánea, lo que parece haber aliviado mis problemas con el interbloqueo. Gracias por su ayuda :) – LaserJesus

-1

No necesita ninguna transacción. La función scope_identity() devolverá el ID creado por última vez en el mismo ámbito, por lo que no hay problema si se ejecuta otro inserto antes de obtener el id, ya que está en un ámbito diferente.

+0

El alcance de la transacción es tal que puedo retrotraer los cambios si algo sale mal en otro lugar, o al menos, cuando finaliza la prueba uni. – LaserJesus

+0

@downvoter: ¿Por qué el voto a favor? Si no dice lo que piensa que está mal, no puede mejorar la respuesta de ninguna manera. – Guffa

0

Compruebe el isolationLevel, que se utiliza en su consulta. Tenga en cuenta que TransactionScope usa Serializable nivel de aislamiento de forma predeterminada (http://msdn.microsoft.com/en-us/library/ms172152.aspx). Intente cambiar el nivel de aislamiento de su transacción a Read Commited.

Cuestiones relacionadas