Je suis actuellement l'insertion d'un enregistrement dans une table SQL Server, puis en sélectionnant l'ID incrémentation automatique comme suit:Pourquoi le blocage SQL Server suivant est-il inséré lors d'une transaction?
(@p0 int,@p1 nvarchar(8))INSERT INTO [dbo].[Tag]([Some_Int], [Tag])
VALUES (@p0, @p1)
SELECT CONVERT(Int,SCOPE_IDENTITY()) AS [value]
(Ceci a été généré en utilisant LINQ to SQL). Pour une raison quelconque lorsque j'exécute ce code dans une transaction utilisant l'objet TransactionScope avec un niveau d'isolation Serializable, SQL Server génère une erreur de blocage. J'ai analysé les événements de graphique de blocage et a constaté que les deux processus impliqués ont été chacun attend de l'autre pour effectuer l'opération de conversion, comme je comprends les informations suivantes:
<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>
Je crois comprendre que la portée de la transaction empêcherait la deuxième processus d'effectuer l'insertion jusqu'à ce que le premier avait terminé à la fois l'insertion et la sélection de l'identité. Cependant, cela ne semble pas être le cas. Quelqu'un pourrait-il faire la lumière sur la meilleure approche pour atteindre ce dont j'ai besoin d'une manière thread-safe?
- Mise à jour -
Juste à noter; Je suis sûr à 99% qu'une connexion n'est pas partagée entre les deux processus car chacun crée un nouveau DataContext pour communiquer avec la base de données.
- Mise à jour Encore une fois -
Remus Rusanu a souligné que certains renseignements omis était lié au problème, j'ai essayé de simplifier le scénario basé sur le rapport de graphique de blocage, mais j'ai étendu l'explication ici. Avant de faire l'insertion, j'effectue une requête exists sur la table en question pour déterminer si la balise existe déjà. Si c'est le cas, je mets fin à la transaction. Si ce n'est pas le cas, j'effectue une mise à jour, non montrée ici, sur une table qui a pour clé primaire Some_Int
, bien que la mise à jour soit purement pour une dernière valeur modifiée. Il peut également être important que la table des balises ait un index cluster composé à la fois de l'identifiant auto inc et de Some_Int. Je ne pensais pas que cette dernière information était pertinente car j'ai essayé de changer la table pour avoir seulement le champ auto inc comme index clé/cluster en vain.
Merci.
Putain bonne question! Je veux voir une réponse. – Chris