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 :

Timeout sql, meme avec Dispose()


Sujet :

Accès aux données

  1. #1
    Invité
    Invité(e)
    Par défaut Timeout sql, meme avec Dispose()
    Bonjour,

    J'ai crée une classe qui me permet d'aller chercher des données en sql, voici la partie qui va nous interesser :

    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
     
    public class DataBase : IDisposable{
    private SqlDataReader reader;
    private SqlCommand _sqlCommand = new SqlCommand();
    public string Requete{get;set;}
    //...
    public DataBase(string connection_string)
            {
                _sqlCommand.Connection = new SqlConnection(connection_string);
            }
    #region IDisposable Membres
            public void Dispose()
            {
                ReleaseReader();
                this.sql_command.Dispose();
                close_connection();
                this.connection.Dispose();
            }
    #endregion
    private void ReleaseReader()
            {
                if (this.reader != null)
                {                
                    this.reader.Dispose();               
                    this.reader = null;
                }
            }
    public bool ExecuteReader()
            {
     
                try
                {
                    OpenConnection();
                    reader = _sqlCommand.ExecuteReader();
     
                    return true;
                }
                catch (Exception ex)
                {
                    this.error = ex;
     
                    CloseConnection();
                    return false;
                }
            }
           public void CloseConnection()
            {
                if (_sqlCommand.Connection.State == ConnectionState.Open)
                    _sqlCommand.Connection.Close();
            }
            public void OpenConnection()
            {
                if (_sqlCommand.Connection.State == ConnectionState.Closed)
                    _sqlCommand.Connection.Open();
            }
     public T GetDataOrDefault<T>(string field)
            {
     
                try
                {
                    object res = this.GetReaderData(field);
                    if (res == DBNull.Value)
                        return default(T);
                    return (T)res;
                }
                catch (InvalidCastException ice)
                {
                        throw new Exception("Erreur de cast de donnée : '" + field + "' de type " + this.reader[field].GetType() + " en " + typeof(T).ToString());
                }
            }
     //retourne faux a la dernière ligne ou si les données n'ont pas étés initialisées
            public bool NextLine()
            {          
                if (this.reader == null || !this.reader.Read())
                {
                    ReleaseReader();                
                    this.sql_command.Dispose();
                close_connection();
                this.connection.Dispose();return false;
     
                }           
                return true;
            }
    //...
    }
    Voici par ex un appel

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    using (DataBase db = new Database("connection string...")){
    db.Requete = "Select nom FROM toto where id = 3";
    db.ExecuteReader();
    if(db.NextLine())
    string nom = db.GetDataOrDefault<string>("nom");
    }
    A la base la classe n'implémentait pas IDisposable, mais je me suis rendu compte que parfois mes collègues ne fermais pas les connection.
    Donc parfois dans le code l'instanciation de DataBase est faite sans le "using", mais comme on le vois dans la methode "NextLine", je fait un controle, et si il n'y a plus de donnée alors je fait la meme chose que dans "Dispose".

    Et pourtant a cause de l'implémentation de "IDisposable" (je suis sur que c'est à cause de cette dernière c'est la suele modification apportée), j'ai par moment, pendant 30min dans la journée, des timeout sur des requète bidons.

    Peut etre que cela viens des appels fait sans le "using" , mais auparavant (quand la classe n'était pas IDisposable), je n'avais pas ces problème la et tout allait bien.

    Avez vous une idée?

  2. #2
    Membre émérite
    Avatar de laedit
    Homme Profil pro
    Consultant études et développement
    Inscrit en
    Décembre 2006
    Messages
    1 344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consultant études et développement
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 344
    Points : 2 265
    Points
    2 265
    Par défaut
    Je pense qu'il te lèverait une NullException plutôt que de te faire un TimeOut si c'était à cause des Dispose de tes composants.

    Cela peut par contre provenir de la base de données, qui serait "encombrées" à certains moments de la journée.
    Blog - Articles - Framework

    MSDN vous aide, si si, alors n'hésitez pas à y faire un tour avant de poser une question.
    Ah, et n'oubliez pas, Google peut répondre à la majorité de vos questions.

  3. #3
    Invité
    Invité(e)
    Par défaut
    Ben je travaille dans le tourisme, et les périodes de charge c'est plutot mi-juillet, la niveau charge on a plus rien, et les procs du cluster de base de donnée sont très très bas. Par exemple mi juin sur la plateforme (qui est web), on était a 23Mo/sec. de 8h a 00h, et j'avais aucun timeout. La on est a 3Mo/sec et j'ai une période de 1h ( a des heures aléatoires) ou j'ai beaucoup de timeouts.

    Et je remarque ça depuis que j'ai fait cette modif (que j'avais fait a la base pour améliorer les perfs ^^)

  4. #4
    Membre émérite
    Avatar de laedit
    Homme Profil pro
    Consultant études et développement
    Inscrit en
    Décembre 2006
    Messages
    1 344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consultant études et développement
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 344
    Points : 2 265
    Points
    2 265
    Par défaut
    Est-ce que tu as remarqué à quel moment il te faisait le timeout ?
    Par exemple est-ce lors du 2° passage dans ReadLine ?

    Et dans quelles conditions ? Exclusivement avec ceux qui utilisent le using ou au contraire si on oublie de fermer la connexion ?
    Blog - Articles - Framework

    MSDN vous aide, si si, alors n'hésitez pas à y faire un tour avant de poser une question.
    Ah, et n'oubliez pas, Google peut répondre à la majorité de vos questions.

  5. #5
    Invité
    Invité(e)
    Par défaut
    Voici le message d'exception :

    StackTrace at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
    at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
    at System.Data.SqlClient.SqlConnection.Open()
    at LibSH.DataBase.OpenConnection()
    at LibSH.DataBase.ExecuteReader()

    Message Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.
    C'est donc lors de l'ouverture de connection.
    Dernière modification par Deepin ; 06/10/2009 à 18h48.

  6. #6
    Membre émérite
    Avatar de laedit
    Homme Profil pro
    Consultant études et développement
    Inscrit en
    Décembre 2006
    Messages
    1 344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consultant études et développement
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 344
    Points : 2 265
    Points
    2 265
    Par défaut
    Apparemment il te recréer une nouvelle connexion à chaque ExecuteReader de ta DataBase jusqu'à aller au maximum de connexions autorisées par le Pool et à ce moment là, il te fait un timeout.

    Fais du pas-à-pas et vérifie si le statut de la connexion de la Command est à Open ou Close dans ta méthode OpenConnection.
    Blog - Articles - Framework

    MSDN vous aide, si si, alors n'hésitez pas à y faire un tour avant de poser une question.
    Ah, et n'oubliez pas, Google peut répondre à la majorité de vos questions.

  7. #7
    Invité
    Invité(e)
    Par défaut
    Le statut est forcément a close :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public void OpenConnection()
            {
                if (_sqlCommand.Connection.State == ConnectionState.Closed)
                    _sqlCommand.Connection.Open();
            }
    Vu que l'exception arrive sur SqlConnection.Open, on passe forcément par "_sqlCommand.Connection.State == ConnectionState.Closed" .

    EDIT : je n'ai vu aucun évènement particulier dans els logs du cluster ou des frontaux web a l'heure de début des timeout, donc c'est pas des reboot ou des arret des service de sql server.

  8. #8
    Membre émérite
    Avatar de laedit
    Homme Profil pro
    Consultant études et développement
    Inscrit en
    Décembre 2006
    Messages
    1 344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consultant études et développement
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 344
    Points : 2 265
    Points
    2 265
    Par défaut
    Il y passe, ça d'accord, mais il faut vérifier si la condition se révèle juste pour voir si c'est bien ici que les connexions s'ouvrent.
    Si c'est ça, tu pourras affirmer que c'est bien le nombre maximum de connexions atteints qui provoquent le timeout.

    Et une fois cela prouvé, tu pourras vérifier tout ton code en debug pas-à-pas afin de voir où est-ce que la connexion passe en Closed alors qu'elle n'est apparemment pas fermée du côté de la base de données.
    Blog - Articles - Framework

    MSDN vous aide, si si, alors n'hésitez pas à y faire un tour avant de poser une question.
    Ah, et n'oubliez pas, Google peut répondre à la majorité de vos questions.

  9. #9
    Invité
    Invité(e)
    Par défaut
    Je vais voir, mais c'est le seul endroit ou je vois pas ou d'autre il pourrait appeler SqlConnection.Close.

    Je viens de debugger un des programmes et a chaques appel de OpenConnection (une dizaine), la connection est fermée.

  10. #10
    Membre émérite
    Avatar de laedit
    Homme Profil pro
    Consultant études et développement
    Inscrit en
    Décembre 2006
    Messages
    1 344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consultant études et développement
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 344
    Points : 2 265
    Points
    2 265
    Par défaut
    Donc si ta connexion est bien fermée à chaque fois, et on va supposer qu'elle l'est correctement, le timeout ne vient donc pas du trop grand nombre de connexions simultanées à la base de données.

    Retour à la case départ, qu'est-ce qui provoque le timeout ?

    Apparemment ni du serveur, ni des connexions, il reste quoi comme option ?


    Comme je l'ai déjà dit, je soupçonne quand même fortement les connexions, il faudrait que tu suive l'état d'une connexion depuis sa création à sa fermeture en déboguant ton application au pas à pas.
    Blog - Articles - Framework

    MSDN vous aide, si si, alors n'hésitez pas à y faire un tour avant de poser une question.
    Ah, et n'oubliez pas, Google peut répondre à la majorité de vos questions.

  11. #11
    Invité
    Invité(e)
    Par défaut
    Sauf que a chaques fois que j'appelle ma classe, je crée une nouvelle instance de SqlConnection, donc c'est normal qu'elle soit fermée, je pense pas que ce soit possible d'avoir une connection ouverte alors qu'on viens de l'instancier.

    En faisant du pas à pas (donc en local, ou je n'ai pas de problème particulier), la connection a une évolution normale : j'instancie un DataBase, je me connecte, je requète, je dispose().

  12. #12
    Expert éminent sénior

    Avatar de Philippe Vialatte
    Homme Profil pro
    Architecte technique
    Inscrit en
    Juillet 2004
    Messages
    3 029
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juillet 2004
    Messages : 3 029
    Points : 12 465
    Points
    12 465
    Par défaut
    Alors, plan B, si tu as des problèmes de connexion, regarde cote serveur le nombre de connexions ouvertes, et qui les a ouvertes (si ca se trouve, ce nést pas ton programme ...mais je doute )

    Et après, il va peut-etre falloir que tu changes ton modele ...parce qu'apparemment, si tu récupères deux lignes, mais que tu n'en traites qu'une, ta connexion reste ouverte...

    Utiliser un datareader, ce n'est pas forcement la bonne maniere de faire, surtout si tu recuperes une seule valeur comme dans ton exemple...dans ce cas la, une methode qui fait un executescalar serait plus appropriee, et si ce n'est pas pour iterer sur les resultats, autant utiliser un dataset/datatable

    Mon Blog

    The Cake is still a lie !!!



    Vous voulez contribuer à la rubrique .NET ? Contactez-moi par MP.
    Vous voulez rédiger des articles pour la rubrique .NET ? Voici la procédure à suivre.

  13. #13
    Membre émérite
    Avatar de laedit
    Homme Profil pro
    Consultant études et développement
    Inscrit en
    Décembre 2006
    Messages
    1 344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consultant études et développement
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 344
    Points : 2 265
    Points
    2 265
    Par défaut
    Vérifie bien que le Dispose soit appelé ou en tout cas que ta connexion se ferme dès que tu n'en as plus besoin (après l'utilisation du DataReader par exemple)
    Blog - Articles - Framework

    MSDN vous aide, si si, alors n'hésitez pas à y faire un tour avant de poser une question.
    Ah, et n'oubliez pas, Google peut répondre à la majorité de vos questions.

  14. #14
    Invité
    Invité(e)
    Par défaut
    Le execute scalar permet de récupérer 1 colonnes de 1 ligne, donc a part pour du 1 shot ...

    Pour la datatable, c'est un choix qu'on a fait pour plusieur raison :
    - perf, de toute manière avec un dataadapter, il va appeler un datareader pour remplir la datatable (j'ai fait des essais et en général , la selection + le mapping vers nos objets métiers est plus rapide avec des reader )
    - virer les datatable du code (j'aime pas trop le coté magic string quand on l'utilise).


    Par contre tu as raison sur le cas ou on va selectionner 2 lignes ,appeler NextLine que 1 fois, et ne pas mettre l'instanciation dans un "using", effectivement, la connection reste ouverte. Mais avant que ma classe DataBase n'implemente IDisposable, tout fonctionnais bien, aussi pourri que ça peut etre.

    A l'heure actuelle la seule solution que je vois, c'est tracer tout mes appels et rajouter un using. j'ai essayé de rajouter un appel a Dispose dans mon destructeur mais ça tue mon serveur de test de VS.

  15. #15
    Expert éminent sénior

    Avatar de Philippe Vialatte
    Homme Profil pro
    Architecte technique
    Inscrit en
    Juillet 2004
    Messages
    3 029
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juillet 2004
    Messages : 3 029
    Points : 12 465
    Points
    12 465
    Par défaut
    Le execute scalar permet de récupérer 1 colonnes de 1 ligne, donc a part pour du 1 shot ...
    Oui, mais bon, comme c'était ton exemple

    Pour la datatable, c'est un choix qu'on a fait...
    Je ne remets pas le choix en question, mais utiliser le datareader fait que tu ne maitrise pas le moment ou tu peux fermer la connection.

    A l'heure actuelle la seule solution que je vois, c'est tracer tout mes appels et rajouter un using. j'ai essayé de rajouter un appel a Dispose dans mon destructeur mais ça tue mon serveur de test de VS.
    Bis, mais si tu regarde cote serveur, tu devrais pouvoir lister toutes les connexions ouvertes, ainsi que leur origine et la derniere requete effectuee...

    Mon Blog

    The Cake is still a lie !!!



    Vous voulez contribuer à la rubrique .NET ? Contactez-moi par MP.
    Vous voulez rédiger des articles pour la rubrique .NET ? Voici la procédure à suivre.

  16. #16
    Invité
    Invité(e)
    Par défaut
    Je viens de regarder dans l"Activity monitor" (moniteur d'activité ^^) , j'ai a peu pres 128 process lancé pour l'application ".net sql data provider".

    La colonne command contiens "awaiting command" et en status j'ai "sleeping" .

    Apres quand je double clicke sur une ligne de process, j'ai la dernière requète effectuée, et la je vois mes requète sql, mais je peut pas dire que y'en a une qui est récurente.

    Je pense que a l'appel de la requète je vais tourner dans le datareader et charges les données dans une list de dictionnary<string,object> et fermer tout ça proprement.

  17. #17
    Membre émérite
    Avatar de laedit
    Homme Profil pro
    Consultant études et développement
    Inscrit en
    Décembre 2006
    Messages
    1 344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consultant études et développement
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 344
    Points : 2 265
    Points
    2 265
    Par défaut
    C'est le mieux à faire, au moins tu seras certain de fermer la connexion et tu pourras conserver la structure de ta classe.
    Blog - Articles - Framework

    MSDN vous aide, si si, alors n'hésitez pas à y faire un tour avant de poser une question.
    Ah, et n'oubliez pas, Google peut répondre à la majorité de vos questions.

  18. #18
    Invité
    Invité(e)
    Par défaut
    Ouai, solution très très bof : j'ai une perte de perf de environ 40%, car je parcours les données 2 fois ... ahhhhhhhhhhh

    PS : j'ai testé avec des datatable, les perfs sont 2 fois pire.

  19. #19
    Membre émérite
    Avatar de laedit
    Homme Profil pro
    Consultant études et développement
    Inscrit en
    Décembre 2006
    Messages
    1 344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consultant études et développement
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 344
    Points : 2 265
    Points
    2 265
    Par défaut
    Bah sinon faut que tu revois ta classe pour obliger la fermeture de la connexion au bout d'un certain temps sans utilisation, ou d'obliger les gens qui utilisent la classe à faire un Dispose().
    Blog - Articles - Framework

    MSDN vous aide, si si, alors n'hésitez pas à y faire un tour avant de poser une question.
    Ah, et n'oubliez pas, Google peut répondre à la majorité de vos questions.

  20. #20
    Expert éminent sénior

    Avatar de Philippe Vialatte
    Homme Profil pro
    Architecte technique
    Inscrit en
    Juillet 2004
    Messages
    3 029
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juillet 2004
    Messages : 3 029
    Points : 12 465
    Points
    12 465
    Par défaut
    Je pense que a l'appel de la requète je vais tourner dans le datareader et charges les données dans une list de dictionnary<string,object> et fermer tout ça proprement.
    Citation Envoyé par Bourgui Voir le message
    Ouai, solution très très bof : j'ai une perte de perf de environ 40%, car je parcours les données 2 fois ... ahhhhhhhhhhh

    PS : j'ai testé avec des datatable, les perfs sont 2 fois pire.
    Euh...la, tu vois, je me dis que tu dois avoir un gros bleme avec tes requetes sql...

    Si tu fais des select * from toto et que tu utilises que la premiere ligne, c'est quand meme un peu ta faute

    Mon Blog

    The Cake is still a lie !!!



    Vous voulez contribuer à la rubrique .NET ? Contactez-moi par MP.
    Vous voulez rédiger des articles pour la rubrique .NET ? Voici la procédure à suivre.

Discussions similaires

  1. Generer du xml via SQL(oracle) avec de l'asp
    Par jpg dans le forum XQUERY/SGBD
    Réponses: 6
    Dernier message: 03/08/2004, 12h36
  2. Connexion à SQL Server avec ASP
    Par ayobo dans le forum ASP
    Réponses: 3
    Dernier message: 25/05/2004, 17h06
  3. attaquer base sql server avec easyphp sous windows
    Par jarod71 dans le forum MS SQL Server
    Réponses: 7
    Dernier message: 11/12/2003, 14h17
  4. [] Datareport.orientation introuvable même avec sp5
    Par khany dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 08/01/2003, 10h06
  5. Réponses: 3
    Dernier message: 18/11/2002, 16h36

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