2009-06-15 8 views
6

Attualmente sto inserendo un record in una tabella di SQL Server e quindi selezionando l'ID di incremento automatico come segue:Perché il seguente SQL Server inserisce deadlock quando viene eseguito all'interno di una transazione?

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

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

(Questo è stato generato utilizzando LINQ to SQL). Per qualche motivo quando eseguo questo codice all'interno di una transazione utilizzando l'oggetto TransactionScope con un livello di isolamento serializzabile, SQL Server genera un errore deadlock. Ho analizzato gli eventi grafico stallo e ha scoperto che i due processi coinvolti sono stati ogni attesa dall'altra per eseguire l'operazione convertito, mi pare di capire le seguenti informazioni:

<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> 

La mia comprensione è che l'ambito della transazione impedirebbe la seconda elaborare dall'esecuzione dell'inserto fino a quando il primo ha terminato sia l'inserimento che la selezione dell'identità. Tuttavia questo non sembra essere il caso. Qualcuno potrebbe far luce sull'approccio migliore per ottenere ciò che richiedo in modo thread-safe?

- Aggiornato -

Basta notare; Sono sicuro al 99% che una connessione non venga condivisa tra i due processi poiché ciascuno crea un nuovo DataContext per comunicare con il database.

- nuovamente aggiornato -

Remo Ruşanu ha sottolineato che alcune informazioni omesse è stato legato al problema, ho cercato di semplificare lo scenario in base al report grafico situazione di stallo, ma ho esteso la spiegazione Qui. Prima di eseguire l'inserimento, eseguo una query esistente sulla tabella in questione per determinare se il tag esiste già. Se lo fa, termino la transazione. In caso contrario, l'inserto dovrebbe andare avanti e quindi eseguirò un aggiornamento, non mostrato qui, su una tabella che ha Some_Int come chiave primaria, sebbene l'aggiornamento sia puramente per un ultimo valore modificato. Potrebbe anche essere importante che la tabella Tag abbia un indice cluster composto sia dall'ID auto inc sia da Some_Int. Non pensavo che questa ultima informazione fosse rilevante dato che ho provato a cambiare la tabella in modo da avere solo il campo auto inc come la chiave primaria/indice cluster inutilmente.

Grazie.

+0

Una bella domanda! Voglio vedere una risposta. – Chris

risposta

7

Il "convert" in questione è un 'lock convert' from RangeS-S to RangeI-N, non correlato alla funzione "CONVERT" in alcun modo. Il fatto che tu abbia i blocchi RangeS-S già inseriti nell'indice PK_Tag_1 indica che stai facendo qualcosa di più di un semplice INSERT. La tua transazione esegue, per caso, una verifica prima di vedere se il nuovo record "esiste" prima di tentare l'inserimento?

+0

davvero ... – LaserJesus

+0

Ho aggiornato la domanda per riflettere la situazione in modo più completo – LaserJesus

+0

Ho modificato il livello di isolamento in istantanea, che sembra aver alleviato i miei problemi di deadlock. Grazie per il tuo aiuto :) – LaserJesus

-1

Non è necessaria alcuna transazione. La funzione scope_identity() restituirà l'ultimo ID creato nello stesso ambito, quindi non c'è alcun problema se un altro inserimento viene eseguito prima di ottenere l'id, poiché è in un ambito diverso.

+0

L'ambito della transazione è così che posso eseguire il rollback delle modifiche se qualcosa va storto altrove, o al minimo, quando termina il test uni. – LaserJesus

+0

@downvoter: perché il downvote? Se non dici quello che pensi sia sbagliato, non può migliorare la risposta in alcun modo. – Guffa

0

Controllare il livello di isolamento, che viene utilizzato nella query. Si noti che TransactionScope utilizza il livello di isolamento serializzabile per impostazione predefinita (http://msdn.microsoft.com/en-us/library/ms172152.aspx). Prova a cambiare il livello di isolamento della tua transazione in Read Commited.