Les journaux d'événements pour mon application .NET montrent qu'il se bloque parfois lors de la lecture de Sql Server. Ceci est généralement très rare car nous avons déjà optimisé nos requêtes pour éviter les blocages, mais ils se produisent parfois encore. Dans le passé, nous avons eu des interblocages qui se produisent lors de l'appel de la fonction ExecuteReader
sur notre instance SqlCommand
. Pour corriger cela, nous avons ajouté le code de nouvelle tentative pour exécuter simplement la requête à nouveau, comme ceci:Comment faire pour récupérer à partir de l'exception deadlock pendant SqlDataReader.Read()
//try to run the query five times if a deadlock happends
int DeadLockRetry = 5;
while (DeadLockRetry > 0)
{
try
{
return dbCommand.ExecuteReader();
}
catch (SqlException err)
{
//throw an exception if the error is not a deadlock or the deadlock still exists after 5 tries
if (err.Number != 1205 || --DeadLockRetry == 0)
throw;
}
}
Cela a fonctionné très bien pour le cas où l'impasse est arrivé lors de la requête initiale exécuter, mais maintenant nous obtenons des interblocages en itérer à travers les résultats en utilisant la fonction Read()
sur le SqlDataReader
retourné.
Encore une fois, je ne suis pas préoccupé par l'optimisation de la requête, mais simplement essayer de récupérer dans le cas rare qu'un blocage se produit. Je pensais à utiliser un processus similaire. Je pourrais créer ma propre classe qui hérite de SqlDataReader
qui remplace simplement la fonction Read
avec le code de réessai. Comme ceci:
public class MyDataReader : SqlDataReader
{
public override bool Read()
{
int DeadLockRetry = 5;
while (DeadLockRetry > 0)
{
try
{
return base.Read();
}
catch (SqlException ex)
{
if (ex.ErrorCode != 1205 || --DeadLockRetry == 0)
throw;
}
}
return false;
}
}
Est-ce la bonne approche? Je veux être sûr que les enregistrements ne sont pas ignorés dans le lecteur. Réessayer Read
après un blocage sauter des lignes? De même, dois-je appeler Thread.Sleep
entre les tentatives pour donner à la base de données le temps de sortir de l'état de blocage, ou est-ce suffisant. Ce cas n'est pas facile à reproduire, donc j'aimerais m'en assurer avant de modifier mon code.
EDIT:
Comme demandé, un peu plus d'informations sur ma situation: Dans un cas, j'ai un processus qui exécute une requête qui charge une liste des ids de disques qui ont besoin d'être mis à jour. Ensuite, je parcourir cette liste d'identifiants en utilisant la fonction Read
et exécuter un processus de mise à jour sur cet enregistrement, qui finira par mettre à jour une valeur pour cet enregistrement dans la base de données. (Non, il n'y a aucun moyen d'effectuer la mise à jour dans la requête initiale, beaucoup d'autres choses se produisent pour chaque enregistrement qui est retourné). Ce code a bien fonctionné pendant un certain temps, mais nous utilisons un peu de code pour chaque enregistrement, donc je peux imaginer qu'un de ces processus crée un verrou sur la table initiale en cours de lecture. Après réflexion, la suggestion de Scottie d'utiliser une structure de données pour stocker les résultats résoudrait probablement cette situation. Je pourrais stocker les ids retournés dans un List<int>
et la boucle à travers cela. De cette façon, les serrures sur les rangées peuvent être enlevées tout de suite.
Cependant, je serais toujours intéressé à savoir s'il existe un moyen général de récupérer des blocages sur une lecture.
Pourriez-vous donner plus d'informations sur votre utilisation de DB? Il est étrange d'avoir une impasse en lisant des données. Cela signifie que votre code contient déjà des verrous pour d'autres données et qu'une autre transaction a verrouillé ce que vous essayez de lire et attend les données auxquelles vous avez déjà accédé. Pouvez-vous appeler ExecuteReader sur une autre transaction? – Timores