IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Accès aux données Discussion :

Deadlock, comment l'éviter ?


Sujet :

Accès aux données

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre extrêmement actif
    Avatar de kedare
    Homme Profil pro
    SRE
    Inscrit en
    Juillet 2005
    Messages
    1 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Espagne

    Informations professionnelles :
    Activité : SRE

    Informations forums :
    Inscription : Juillet 2005
    Messages : 1 549
    Par défaut Deadlock, comment l'éviter ?
    Hello,
    J'ai un petit problème, j'ai un système de bot IRC qui utilise 2 applications et une base de données,
    D'un coté j'ai le bot IRC qui gère l"accès aux données via ce fichier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Data.SqlClient;
    using System.Data;
     
    namespace IronViper
    {
        class DatabaseHandler
        {
            private SqlConnection connection;
     
            public DatabaseHandler(string connectionString)
            {
                this.connection = new SqlConnection(connectionString);
                this.connection.Open();
                Console.WriteLine("Connected to database !");
            }
     
            public bool UpdateChannel(string channel)
            {
                // Let's check if the channel is already in the database.
                SqlCommand checkCommand = new SqlCommand("SELECT Count(*) AS Count FROM Channels WHERE Name = @ChannelName", this.connection);
                checkCommand.Parameters.Add(new SqlParameter("@ChannelName", SqlDbType.VarChar));
                checkCommand.Parameters["@ChannelName"].Value = channel;
                SqlDataReader result = checkCommand.ExecuteReader();
                result.Read();
                int doesItExists = (int)result["Count"];
                result.Close();
                if (doesItExists == 0)
                {
                    // If not, we register it.
                    SqlCommand registerCommand = new SqlCommand("INSERT INTO Channels(Name) VALUES (@ChannelName)", this.connection);
                    SqlTransaction transaction = this.connection.BeginTransaction(IsolationLevel.ReadUncommitted);
                    registerCommand.Transaction = transaction;
                    registerCommand.Parameters.Add(new SqlParameter("@ChannelName", SqlDbType.VarChar));
                    registerCommand.Parameters["@ChannelName"].Value = channel;
                    registerCommand.ExecuteNonQuery();
                    transaction.Commit();
                    return false;
                }
                else
                {
                    // If yes, we update it
                    SqlCommand registerCommand = new SqlCommand("UPDATE Channels SET LastActivity=GetDate() WHERE Name = @ChannelName", this.connection);
                    SqlTransaction transaction = this.connection.BeginTransaction(IsolationLevel.ReadUncommitted);
                    registerCommand.Transaction = transaction;
                    registerCommand.Parameters.Add(new SqlParameter("@ChannelName", SqlDbType.VarChar));
                    registerCommand.Parameters["@ChannelName"].Value = channel;
                    registerCommand.ExecuteNonQuery();
                    transaction.Commit();
                    return true;
                }
            }
     
            public bool UpdateUser(string user, string host)
            {
                // Let's check if the user is already in the database.
                SqlCommand checkCommand = new SqlCommand("SELECT Count(*) AS Count FROM Users WHERE Name=@UserName AND Host = @HostName", this.connection);
                checkCommand.Parameters.Add(new SqlParameter("@UserName", SqlDbType.VarChar));
                checkCommand.Parameters.Add(new SqlParameter("@HostName", SqlDbType.VarChar));
                checkCommand.Parameters["@UserName"].Value = user;
                checkCommand.Parameters["@HostName"].Value = host;
                SqlDataReader result = checkCommand.ExecuteReader();
                result.Read();
                int doesItExists = (int)result["Count"];
                result.Close();
                if (doesItExists == 0)
                {
                    // If not, we register it.
                    SqlCommand registerCommand = new SqlCommand("INSERT INTO Users(Name,Host) VALUES (@UserName, @HostName)", this.connection);
                    SqlTransaction transaction = this.connection.BeginTransaction(IsolationLevel.ReadUncommitted);
                    registerCommand.Transaction = transaction;
                    registerCommand.Parameters.Add(new SqlParameter("@UserName", SqlDbType.VarChar));
                    registerCommand.Parameters.Add(new SqlParameter("@HostName", SqlDbType.VarChar));
                    registerCommand.Parameters["@UserName"].Value = user;
                    registerCommand.Parameters["@HostName"].Value = host;
                    registerCommand.ExecuteNonQuery();
                    transaction.Commit();
                    return false;
                }
                else
                {
                    // If yes, we update it
                    SqlCommand registerCommand = new SqlCommand("UPDATE Users SET LastActivity=GetDate() WHERE Name=@UserName AND Host = @HostName", this.connection);
                    SqlTransaction transaction = this.connection.BeginTransaction(IsolationLevel.ReadUncommitted);
                    registerCommand.Transaction = transaction;
                    registerCommand.Parameters.Add(new SqlParameter("@UserName", SqlDbType.VarChar));
                    registerCommand.Parameters.Add(new SqlParameter("@HostName", SqlDbType.VarChar));
                    registerCommand.Parameters["@UserName"].Value = user;
                    registerCommand.Parameters["@HostName"].Value = host;
                    registerCommand.ExecuteNonQuery();
                    transaction.Commit();
                    return true;
                }
            }
     
            public void RegisterMessage(string message, string channel, string user, string host)
            {
     
                // We register the message
                SqlCommand registerCommand = new SqlCommand("INSERT INTO Messages(Data,UserId,ChannelId) VALUES (@Message, (SELECT Id FROM Users WHERE Name=@UserName AND Host=@HostName), (SELECT Id FROM Channels WHERE Name=@ChannelName)) ", this.connection);
                SqlTransaction transaction = this.connection.BeginTransaction(IsolationLevel.ReadUncommitted);
                registerCommand.Transaction = transaction;
                registerCommand.Parameters.Add(new SqlParameter("@Message", SqlDbType.VarChar));
                registerCommand.Parameters.Add(new SqlParameter("@UserName", SqlDbType.VarChar));
                registerCommand.Parameters.Add(new SqlParameter("@ChannelName", SqlDbType.VarChar));
                registerCommand.Parameters.Add(new SqlParameter("@HostName", SqlDbType.VarChar));
                registerCommand.Parameters["@Message"].Value = message;
                registerCommand.Parameters["@UserName"].Value = user;
                registerCommand.Parameters["@ChannelName"].Value = channel;
                registerCommand.Parameters["@HostName"].Value = host;
                registerCommand.ExecuteNonQuery();
                transaction.Commit();
            }
        }
    }
    Et de l'autre j'ai une application ASP.NET MVC 2 qui utilise Entity Framework pour gérer les données (lecture seule), seulement de temps en temps sur cette application, j'ai cette erreur :
    System.Data.SqlClient.SqlException
    Transaction (Process ID 52) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
    Voila un exemple de requete LINQ qui peut retourner cette erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    var messages = (from globalView in db.GlobalViews orderby globalView.MessagePostDate descending select globalView).Skip(page*perPage).Take(perPage);
    Je sais pas trop quoi faire...
    Que faire ?

    Merci !

  2. #2
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Février 2005
    Messages
    1 273
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 1 273
    Par défaut
    Vu ce que tu obtiens, changer ton niveau d'isolation me parait la seule solution.
    En fait si tu fais juste de la lecteur avec EF ça devrait fonctionner.

    Ce qui t'arrive est simple :
    - Ton prog 1 fait des transaction SQL
    - Ton prog 2 fait des selects sur des éléments en cours de transaction dans 1
    - Ton prog 2 prend le dead lock dans la face.

    Tu peux aussi regarder ça :
    SQL direct dans EF et utiliser un SELECT WITH NO LOCK pour que ton select ne provoque pas de dead lock

    Et sinon ça (là je décline toute responsabilité !)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    private static TonObjectContext CommeTuveux()
    { 
            TonObjectContext ctx= new TonObjectContext (); 
            ctx.ExecuteStoreCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;"); 
            return ctx; 
     }

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 5
    Dernier message: 20/10/2006, 13h16
  2. Logiciel de filtre web. Comment les éviter
    Par babemagus dans le forum Applications
    Réponses: 3
    Dernier message: 03/03/2006, 17h38
  3. Problemes de doublons...comment les éviter?
    Par paflolo dans le forum Langage SQL
    Réponses: 5
    Dernier message: 28/02/2006, 14h57
  4. Réponses: 8
    Dernier message: 16/06/2005, 13h58
  5. Fonction template virtuelle... comment l'éviter ?
    Par :Bronsky: dans le forum Langage
    Réponses: 12
    Dernier message: 07/06/2005, 14h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo