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

 MySQL Discussion :

[MySQL5.5][C#] Acces concurrents


Sujet :

MySQL

  1. #1
    Membre confirmé
    Profil pro
    Étudiant
    Inscrit en
    Mai 2009
    Messages
    102
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2009
    Messages : 102
    Par défaut [MySQL5.5][C#] Acces concurrents
    Salut à tou(te)s !

    Voici la situation:

    -j'ai un serveur mysql5.5 fraichement installé et configuré. Ainsi que mysql workbench.

    -j'ai créé une BDD (moteur innoDB) contenant une table. Dans cette table j'ai une clé formée par un couple (vendor_id, service_id), plus un autre champs qui représente un numéro de série en fonction du couple précédent.

    -Le but est de se connecter à la table en question (depuis un client C#) et de pouvoir récupérer un numéro de série puis l'incrémenter. Le numéro de série doit être unique.
    ça se complique dès que je veux passer à plusieurs clients qui demandent des numéros de série.
    j'ai lancé par exemple deux clients qui demandent un numéro de série (Select sur le champs en question de la base) puis qui incrémentent la valeur du champ en question. Tout ça dans une boucle "for".
    Les deux clients que j'ai lancé en simultané se sont jusqu'ici attribué des numéros de série déjà utilisés.

    Le problème vient certainement du fait qu'il y a des accès concurrents et qu'entre la lecture du champ et sa mise à jour les autres clients accèdent au champ.
    Je n'ai pas réussi pour le moment à locker la ligne entre le moment ou un client la lit et la modifie. De sorte que les autres clients ne puissent pas prendre une valeur non à jour.

    J'espère que c'est assez clair, et que vous aurez des idées.

    Bonne soirée, et merci d'avance !

  2. #2
    Invité
    Invité(e)
    Par défaut
    Bonsoir,

    Le mieux à mon avis c'est de laisser MySQL affecter le numéro de série lui-même à l'aide d'un auto-incrément.

  3. #3
    Membre confirmé
    Profil pro
    Étudiant
    Inscrit en
    Mai 2009
    Messages
    102
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2009
    Messages : 102
    Par défaut
    Si je ne me trompe pas, l'auto-incrément s'utilise dans le cas d'un nouvel enregistrement dans la table. Alors l'index de cette table s'auto-incrémente pour la nouvelle ligne.

    Dans mon cas, je souhaiterais uniquement modifier l'enregistrement en question (la ligne) en incrémentant le champ représentant le numéro de série. Et non pas créer un nouvel enregistrement dans la table.

  4. #4
    Expert éminent
    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 818
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 818
    Billets dans le blog
    14
    Par défaut
    -Le but est de se connecter à la table en question (depuis un client C#) et de pouvoir récupérer un numéro de série puis l'incrémenter. Le numéro de série doit être unique.
    Pourquoi ne pas faire simplement la requête suivante ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    UPDATE ta_table
    SET num_serie = num_serie + 1
    WHERE vendor_id = [l_id_vendeur_voulu]
      AND service_id = [l_id_service_voulu]
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole, en retraite... mais toujours Autoentrepreneur à l'occasion.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  5. #5
    Membre confirmé
    Profil pro
    Étudiant
    Inscrit en
    Mai 2009
    Messages
    102
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2009
    Messages : 102
    Par défaut
    Citation Envoyé par CinePhil Voir le message
    Pourquoi ne pas faire simplement la requête suivante ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    UPDATE ta_table
    SET num_serie = num_serie + 1
    WHERE vendor_id = [l_id_vendeur_voulu]
      AND service_id = [l_id_service_voulu]
    Et bien merci pour cette réponse ça marche bien mieux, mais il subsiste un gros problème.

    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
     
            static void Main(string[] args)
            {
                string MyConString = "Database=test;Data Source=localhost;User Id=toto;Password=toto";
                MySqlDataAdapter MyAdapter = new MySqlDataAdapter();
    		    DataSet ds = new DataSet();
     
                try
                {
                    for (int cpt = 0; cpt < 1000; cpt++)
                    {
                        string myUpdateQuery = "UPDATE `test`.`nom` SET `serial`= serial +1 WHERE `idnom`='1'";
                        string mySelectQuery = "Select serial from nom where idnom=1 for update";
     
                        MySqlConnection connection = new MySqlConnection(MyConString);
                        MySqlCommand command = new MySqlCommand(mySelectQuery, connection);
                        MySqlCommand cmd = new MySqlCommand(myUpdateQuery, connection);
                        connection.Open();                    
                        MySqlDataReader Reader;
                        Reader = command.ExecuteReader();
                        Console.WriteLine("APPLI 2");
                        while (Reader.Read())
                        {
                            string thisrow = "";
                            for (int i = 0; i < Reader.FieldCount; i++)
                                thisrow += "serial2 : "+Reader.GetValue(i).ToString();
                            Console.WriteLine(thisrow);
                        }
                        Reader.Close();
                        System.Threading.Thread.Sleep(5000);
                        cmd.ExecuteScalar();
                        connection.Close();
                    }
     
                    Console.Read();
                }
                catch (MySqlException ex) { Console.WriteLine(ex); }
            }

    Voici le code C# pour faire mes tests.
    J'ai mis délibérément un sleep de 5 secs entre l'envoi des deux requêtes au serveur pour voir si c'est sécurisé.
    J'ai deux clients en parallèle avec le même code. Le problème est qu'il n'y a aucune sécurité entre le SELECT pour lire la valeur courante du SN et la requête update. Si mon deuxième client tape en lecture sur la table entre les deux requêtes du premier client il aura un numéro déjà donné au premier client.
    N'y a-t-il pas un mécanisme ( transaction ? ) pour verrouiller la table entre ces deux requêtes ?

    Bon apparemment j'ai trouvé la solution...
    Il fallait désactiver le autocommit en rajoutant un "START TRANSACTION" au debut du script et un "COMMIT" à la fin.
    Dites moi ce que vous en pensez...

    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
     
     
                    for (int cpt = 0; cpt < 1000; cpt++)
                    {
    string lockQuery = "Start transaction";
    string mySelectQuery = "Select serial from nom where idnom=1 for update";
    string myUpdateQuery = "UPDATE `test`.`nom` SET `serial`= serial + 1 WHERE `idnom`='1'";
    string commitQuery = "Commit";
     
                        MySqlConnection connection = new MySqlConnection(MyConString);
                        MySqlCommand command = new MySqlCommand(mySelectQuery, connection);
                        MySqlCommand cmd = new MySqlCommand(myUpdateQuery, connection);
                        MySqlCommand cmd1 = new MySqlCommand(lockQuery, connection);
                        MySqlCommand cmd2 = new MySqlCommand(commitQuery, connection);
     
                        connection.Open();
     
                        cmd1.ExecuteScalar(); // START TRANSACTION
     
                        MySqlDataReader Reader;
                        Reader = command.ExecuteReader(); // SELECT FOR UPDATE QUERY
                        Console.WriteLine("APPLI 1");
                        while (Reader.Read())
                        {
                            string thisrow = "";
                            for (int i = 0; i < Reader.FieldCount; i++)
                                thisrow += "serial : "+Reader.GetValue(i).ToString();
                            Console.WriteLine(thisrow);
                        }
                        Reader.Close();
                        cmd.ExecuteScalar(); // UPDATE QUERY
                        System.Threading.Thread.Sleep(1000);
                        cmd2.ExecuteScalar();// COMMIT
                        connection.Close();
                    }
    Ceci a l'air de marcher car lorsque je mets un délai entre le select et le update d'un client, la boucle for du deuxième se synchronise avec le premier. Les requêtes du deuxième client sont bien mises en attente jusqu'à ce que le premier libère la ligne en faisant le "commit".

  6. #6
    Expert éminent
    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 818
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 818
    Billets dans le blog
    14
    Par défaut
    Ne connaissant pas C# et en regardant rapidement le code, j'ai du mal à comprendre l'utilité du SELECT mais bon...
    Si ça fonctionne comme tu le souhaites, n'oublie pas de marquer
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole, en retraite... mais toujours Autoentrepreneur à l'occasion.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  7. #7
    Membre confirmé
    Profil pro
    Étudiant
    Inscrit en
    Mai 2009
    Messages
    102
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2009
    Messages : 102
    Par défaut
    Salut !
    Le but premier du client c# est de récupérer le serial number stocké dans la base de données... D'où le sélect...
    Ensuite il incrémente la valeur et met a jour la table...

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

Discussions similaires

  1. accés concurrent à une table
    Par shout dans le forum Oracle
    Réponses: 5
    Dernier message: 06/10/2005, 10h54
  2. Réponses: 22
    Dernier message: 25/08/2005, 16h03
  3. Lenteur et acces concurrent
    Par JeanMarc_T2k dans le forum Bases de données
    Réponses: 7
    Dernier message: 04/12/2004, 20h57
  4. acces concurrent avec delphi 5 entreprise
    Par Jean_paul dans le forum Bases de données
    Réponses: 2
    Dernier message: 30/11/2004, 20h19
  5. [EJB] Accès concurrents à la base de données
    Par cameleon2002 dans le forum Java EE
    Réponses: 10
    Dernier message: 23/09/2003, 11h31

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