web-dev-qa-db-fra.com

La transaction (ID de processus) était bloquée sur les ressources verrouillées avec un autre processus et a été choisie comme victime du blocage. Relancez la transaction

J'ai une application C # qui insère des données dans une table SQL Server (2008) à l'aide d'une procédure stockée. J'utilise le multi-threading pour le faire. La procédure stockée est appelée depuis le thread . Ma procédure stockée utilise maintenant "tablock" lors de l'insertion de données . Lors de l'exécution de ce code, l'erreur suivante s'affiche: "Transaction (ID de processus) a été bloqué sur les ressources de verrouillage avec un autre processus et a été choisi comme victime du blocage. Relancez la transaction. "

Quelqu'un peut-il m'aider s'il vous plaît avec n'importe quelle solution à cela?

16
user1018213

Cela se produit lorsque deux processus SQL Server accèdent aux mêmes ressources, mais dans un ordre différent. Par conséquent, ils finissent tous les deux par attendre l'autre processus, ce qui est une impasse.

Il existe un certain nombre de moyens pour le prévenir, notamment: 

  • Évitez de prendre des serrures inutiles. Vérifiez le niveau d'isolation de transaction requis pour la requête, utilisez le repère de verrouillage with (nolock) pour les requêtes, le cas échéant.
  • Assurez-vous que lorsque vous prenez des verrous, vous prenez des verrous sur les objets dans le même ordre dans chaque requête.

Par exemple. si Proc1 verrouille table1 puis table2, mais que Proc2 verrouille table2 puis table1, le problème peut survenir. Vous pouvez réécrire l'un ou l'autre proc pour prendre des verrous dans le même ordre afin d'éviter ce problème.

13
Ben

Vous pouvez encapsuler votre requête dans un bloc TRY CATCH et intercepter des numéros d'erreur (liés aux verrous).

  1. 1204
  2. 1205
  3. 1222

Ensuite, vous pouvez automatiser les tentatives, jusqu’à un certain nombre. Vous feriez donc quelque chose comme ce qui suit:

         DECLARE @RetryNo Int = 1
     ,@RetryMaxNo Int = 5;
   WHILE @RetryNo < @RetryMaxNo
      BEGIN
         BEGIN TRY 

         -- put your query that generates locks here....

            SELECT   @RetryNo = @RetryMaxNo;
         END TRY
         BEGIN CATCH
            IF ERROR_NUMBER() IN (1204, 1205, 1222)
               BEGIN
                  SET @RetryNo += 1;
                  -- it will wait for 10 seconds to do another attempt
                  WAITFOR DELAY '00:00:10';
               END 
            ELSE
               THROW;
         END CATCH
      END 

Vous pouvez également utiliser des indicateurs de table tels que UPDLOCK .

4
Mez

Soyez sûr du champ que vous allez mettre à jour ou insérer, ce champ a un index non clusterisé. S'il n'est pas disponible, vous pouvez d'abord créer un index non clusterisé de ce champ sur cette table, puis créer les étapes ci-dessous.

  • Faites un clic droit sur la table et sélectionnez les propriétés.

  • Sélectionnez Option dans le panneau de droite dans les propriétés.

  • Dans l'onglet Verrou, autoriser le verrouillage de page, indiquez 'Faux' et Autoriser le verrouillage de ligne, la valeur étant 'True', puis appuyez sur OK. 

  • Appuyez sur le bouton Nouvelle requête et écrivez Commande 'update statistics nom de table' et exécutez
  • Reconstruire un index non clusterisé.
0
Naveen Soni

Voici une solution de MSDN par S Kumar Dubey

https://social.msdn.Microsoft.com/Forums/sqlserver/fr-171d9fa9-0a39-48ce-bc38-35623e0c1075/how-can-i-release-lock-on-tables?forum=transactsql

Exécutez SP: SP_LOCK dans les résultats, vous obtiendrez SPID, DBID, OBJID, INDID, TYPE, RESSOURCE, MODE, ÉTAT Maintenant, vérifiez la colonne d’état, si elle est montrant attendre puis tuez ce SPID. Pour tuer un SPID particulier, exécutez SP: Kill 65 (où 65 est SPID)

Il semble que vous ayez besoin d'être l'administrateur du serveur SQL pour résoudre ce problème.

0
Decula

vous pouvez utiliser depuis l'objet Lock

     static object _lock = new object();
    public static void _main()
    {
            lock (_lock)
            {
                _bulkcopy(myData);
            }
    }
    public static void _bulkcopy(DataTable dt)
    {
        try
        {
            using (var connection = new SqlConnection(ConfigurationSettings.AppSettings.Get("DBConnection")))
            {
                connection.Open();
                SqlTransaction transaction = connection.BeginTransaction();

                using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
                {
                    bulkCopy.BatchSize = 100;
                    bulkCopy.DestinationTableName = "dbo.MyTable";
                    try
                    {
                        bulkCopy.WriteToServer(dt);
                    }
                    catch (Exception)
                    {
                        transaction.Rollback();
                        connection.Close();
                    }
                }

                transaction.Commit();
            }




        }
        catch { }
    }
0
xfar

vous devez concevoir des modules de base de données de manière à minimiser les risques de blocages. Voici quelques conseils utiles sur la façon de procéder: Assurez-vous que les applications accèdent à tous les objets partagés dans le même ordre.

Ici, vous pouvez en voir plus et apprendre beaucoup de moyens utiles pour éviter une impasse

0
Shuhratjan Nizamov