Précédent   Forum des professionnels en informatique > Bases de données > MySQL > Débuter
Débuter Forum d'entraide pour débuter avec MySQL
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 11/03/2011, 21h16   #1
Nouveau Membre du Club
 
Étudiant
Inscription : mai 2009
Messages : 102
Détails du profil
Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : mai 2009
Messages : 102
Points : 37
Points : 37
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 !
Xploit est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/03/2011, 22h16   #2
Membre Expert
 
Avatar de Nudger
 
Homme Thomas Arnaud
Directeur de projet
Inscription : octobre 2010
Messages : 452
Détails du profil
Informations personnelles :
Nom : Homme Thomas Arnaud
Âge : 36
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Directeur de projet
Secteur : High Tech - Produits et services télécom et Internet

Informations forums :
Inscription : octobre 2010
Messages : 452
Points : 1 012
Points : 1 012
Envoyer un message via Skype™ à Nudger
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.
__________________
www.nudge.org Surveillez et optimisez vos applications Java
Nudger est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/03/2011, 22h35   #3
Nouveau Membre du Club
 
Étudiant
Inscription : mai 2009
Messages : 102
Détails du profil
Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : mai 2009
Messages : 102
Points : 37
Points : 37
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.
Xploit est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/03/2011, 23h16   #4
Modérateur
 
Avatar de CinePhil
 
Homme Philippe Leménager
Ingénieur d'études en informatique
Inscription : août 2006
Messages : 10 998
Détails du profil
Informations personnelles :
Nom : Homme Philippe Leménager
Âge : 48
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 : 10 998
Points : 18 262
Points : 18 262
Envoyer un message via MSN à CinePhil
Citation:
-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 :
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 de Formation Agronomique.
Mon blog sur la conception des BDD, le langage SQL, le PHP avec Zend Framework...
« 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 Mandriva Linux ou Mageïa ! Soutenons l'industrie logicielle française !
Linuxiens, comptez-vous !
CinePhil est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 12/03/2011, 08h37   #5
Nouveau Membre du Club
 
Étudiant
Inscription : mai 2009
Messages : 102
Détails du profil
Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : mai 2009
Messages : 102
Points : 37
Points : 37
Citation:
Envoyé par CinePhil Voir le message
Pourquoi ne pas faire simplement la requête suivante ?
Code :
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 :
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 :
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".
Xploit est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 14/03/2011, 09h36   #6
Modérateur
 
Avatar de CinePhil
 
Homme Philippe Leménager
Ingénieur d'études en informatique
Inscription : août 2006
Messages : 10 998
Détails du profil
Informations personnelles :
Nom : Homme Philippe Leménager
Âge : 48
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 : 10 998
Points : 18 262
Points : 18 262
Envoyer un message via MSN à CinePhil
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 de Formation Agronomique.
Mon blog sur la conception des BDD, le langage SQL, le PHP avec Zend Framework...
« 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 Mandriva Linux ou Mageïa ! Soutenons l'industrie logicielle française !
Linuxiens, comptez-vous !
CinePhil est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 14/03/2011, 13h16   #7
Nouveau Membre du Club
 
Étudiant
Inscription : mai 2009
Messages : 102
Détails du profil
Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : mai 2009
Messages : 102
Points : 37
Points : 37
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...
Xploit est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 00h22.


 
 
 
 
Partenaires

Hébergement Web