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

SQL Procédural MySQL Discussion :

Générer ou vérifier code unique


Sujet :

SQL Procédural MySQL

  1. #1
    Candidat au Club
    Inscrit en
    Mars 2010
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Mars 2010
    Messages : 21
    Points : 4
    Points
    4
    Par défaut Générer ou vérifier code unique
    Bonjour a tous,

    J'utilise mysql innodb pour une application. Je debute avec mysql (avec les bases de donnees en general). Voici mon probleme:

    J'ai deux connections independantes (dans des threads/processus differents) qui veulent rajouter une ligne dans une table. Pour rajouter une ligne, je dois au prealable generer un id unique sous forme de chaine de caracteres.

    Avant de faire mon INSERT, je fais un select pour chercher un ID unique. Le problement est que si les 2 threads tentent de creer une nouvelle ligne en meme temps, j'ai un risque de creation du meme ID. Pour cela, je pense que je dois locker la table entiere avant de chercher le nouvel ID. Et je delock la table apres le INSERT.

    Est-ce la bonne facon de faire?

    Merci d'avance,

    madric

  2. #2
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    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 799
    Points : 34 046
    Points
    34 046
    Billets dans le blog
    14
    Par défaut
    Si ton "id unique sous forme de chaine de caracteres" est la clé primaire de la table, c'est un mauvais choix !

    Si c'est une clé alternative, significative pour le domaine (une référence, un code, un numéro de série structuré...), alors utilise un TRIGGER BEFORE INSERT. Ainsi, la transaction est maître de la table pour déterminer le code alphanumérique à créer et à intégrer dans la requête INSERT.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    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 !

  3. #3
    Candidat au Club
    Inscrit en
    Mars 2010
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Mars 2010
    Messages : 21
    Points : 4
    Points
    4
    Par défaut
    Merci pour ta reponse.

    Je vais regarder le TRIGGER_BEFORE.
    C'est effectivement une clef alternative.

    J'utilise le driver ODBC pour mysql. J'utilise des transactions et je lis dans la documentation que LOCK TABLES n'est pas compatibles avec les transactions et que son utilisation principale est justement l'emulation de transactions. En quoi les transactions peuvent permettre de se passer des locks de tables? Je peux avoir deux transactions concurrentes.

  4. #4
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    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 799
    Points : 34 046
    Points
    34 046
    Billets dans le blog
    14
    Par défaut
    Tu vas soumettre une requête INSERT.
    Le SGBD bloque la table pour traiter la requête.
    Il remarque qu'il y a un TRIGGER BEFORE INSERT sur cette table et l'exécute, ce qui permet de calculer en toute sécurité la clé alternative à insérer tant que la table est bloquée pour cette transaction.
    Une fois l'insertion effectuée, le SGBD libère la table pour l'autre processus qui patientait à la porte en se rongeant les ongles !
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    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
    Candidat au Club
    Inscrit en
    Mars 2010
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Mars 2010
    Messages : 21
    Points : 4
    Points
    4
    Par défaut
    C'est realisable en passant avec le driver ODBC?

  6. #6
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    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 799
    Points : 34 046
    Points
    34 046
    Billets dans le blog
    14
    Par défaut
    Je pense que oui puisque tout se passe dans le serveur MySQL. ODBC ne fait que transmettre la requête et attendre le résultat. C'est comme une insertion normale sauf que le SGBD fait un boulot en plus qu'une simple insertion.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    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
    Candidat au Club
    Inscrit en
    Mars 2010
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Mars 2010
    Messages : 21
    Points : 4
    Points
    4
    Par défaut
    Sympa ce system de trigger.
    Mais j'ai du mal a ecrire mon trigger...

    Dans MySQL workbench, a ma table, dans le tab "Triggers", j'ai ecris:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    -- Trigger DDL Statements
    DELIMITER $$
     
    USE `OSSITEDB`$$
     
    CREATE TRIGGER CheckUniqueID 
    BEFORE INSERT ON `PREFERENCE_SETS`

    Ensuite ca se complique... Rien ne passe a la syntax. Je voudrais faire un truc du style:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SELECT COUNT(ID) INTO total FROM PREFERENCE_SETS WHERE ID='ID DANS LE INSERT" AND SEQSITE="SEQSITE DANS LE INSERT"
    IF total > 0 THEN ANNULER LE INSERT
    Je ne sais pas comment ecrire ca avec la bonne syntax, tout me semble refuser... Saurais tu comment faire? (je sais j'abuse, mais aucun des exemples que je trouve sur google ne correspond a ce que je veux).

    Encore merci...

  8. #8
    Candidat au Club
    Inscrit en
    Mars 2010
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Mars 2010
    Messages : 21
    Points : 4
    Points
    4
    Par défaut
    mumm, plus je regarde les triggers, plus je me demande si ca correspond a ce dont j'ai besoin. Peut-on vraiment annuler l'INSERT avec les triggers?

  9. #9
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    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 799
    Points : 34 046
    Points
    34 046
    Billets dans le blog
    14
    Par défaut
    J'ai un gros doute sur la nature de ton besoin !
    Dans le premier message, tu disais ceci :
    Pour rajouter une ligne, je dois au prealable generer un id unique sous forme de chaine de caracteres.
    Maintenant, tu essaies de créer ce trigger :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CREATE TRIGGER CheckUniqueID
    Tu veux créer l'identifiant ou juste vérifier qu'il n'existe pas déjà ?

    mumm, plus je regarde les triggers, plus je me demande si ca correspond a ce dont j'ai besoin. Peut-on vraiment annuler l'INSERT avec les triggers?
    Je ne suis pas un habitué des triggers mais effectivemetn il me semble avoir déjà rencontré ce genre de souci avec MySQL !
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    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 !

  10. #10
    Candidat au Club
    Inscrit en
    Mars 2010
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Mars 2010
    Messages : 21
    Points : 4
    Points
    4
    Par défaut
    ok, je vais essayer d'expliquer plus clairement ce que je veux faire.

    J'ai une table "PREFERENCES" qui a une clef primaire de type INTEGER en auto incrementation. Ensuite, les preferences sont rattachees a un utilisateur, j'ai une clef etrangere de type INTEGER qui y correspond. Ensuite, j'ai besoin d'un ID pour la preference, sous forme de chaine de caractere. Je veux que cet ID soit unique pour un utilisateur (un meme ID peut-etre utilise si les utilisateurs sont differents -> cle etrangere differente).

    Ce que je fais, surement pas terrible mais en gros:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    START TRANSACTION
    int index = 1; 
    string id;
    while (1) {
          id = "PREF%index"; (PREF1, PREF2, PREF3...)
          SELECT COUNT(ID) AS RESULT FROM PREFERENCES WHERE ID=id AND USERSEQ = x;
          if (result == 0) break;
          index++;
    }
     
    INSERT INTO PREFERENCES ID=id USERSEQ=x
    COMMIT TRANSACTION
    Voila, j'espere que c'est assez clair.
    Je veux pouvoir etre sur que mon id soit unique. Si 2 threads executent ce bout de code en meme temps, je peux me retrouver avec un id identique.

    L'idee avec le trigger serait alors ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    START TRANSACTION
    int index = 1; 
    string id;
    while (1) {
          id = "PREF%index"; (PREF1, PREF2, PREF3...)
          if (INSERT INTO PREFERENCES ID=id USERSEQ=x) == SUCESS) break;
          index++;
    }
    COMMIT TRANSACTION
    A moins que je ne me trompe completement, c'est comme ca que je voyais les choses.

  11. #11
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    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 799
    Points : 34 046
    Points
    34 046
    Billets dans le blog
    14
    Par défaut
    Si j'ai bien compris, tu veux que le couple {identifiant_utilisateur, id_preference} soit unique ?

    La table "PREFERENCES" est-elle issue d'une association du MCD ? Autrement dit, est-ce une table associative ?
    Si oui : fais du couple la clé primaire de la table.
    Si non : ajoute simplement un index unique sur le couple de colonnes.

    On peut avoir la structure de la table "PREFERENCES" et la description de l'association entre utilisateur et préférence ?

    Quelques billets à lire :
    - pour bien écrire les règles de gestion des données ;
    - pour savoir s'il faut faire une table associative et comment la faire.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    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 !

  12. #12
    Candidat au Club
    Inscrit en
    Mars 2010
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Mars 2010
    Messages : 21
    Points : 4
    Points
    4
    Par défaut
    Je ne sais pas ce qu'est une table associative. Je vais lire tes liens.

    Le truc en plus, c'est que l'ID peut-etre propose par le client, je ne peux donc pas me satisfaire d'une generation automatique.
    Dans les deux propositions que tu me fais, il me semble que ca assure que la bdd refusera la creation d'un couple (user,id) si il existe deja. Mon probleme se trouve en amont, au niveau de la creation de l'id. A moins que tu veuilles me dire qu'il suffit de laisser la bdd le soin de tester ca a ma place. Ce qui reviendrait a un truc du syle:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    START TRANSACTION
    int INDEX = 1; 
    string id;
    while (1) {
          id = "PREF%index"; (PREF1, PREF2, PREF3...)
          IF (INSERT INTO PREFERENCES ID=id USERSEQ=x) == SUCESS) break;
          INDEX++;
    }
    COMMIT TRANSACTION
    et donc la, pas besoin de trigger si je fais du couple (user,id) la clef primaire.

  13. #13
    Candidat au Club
    Inscrit en
    Mars 2010
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Mars 2010
    Messages : 21
    Points : 4
    Points
    4
    Par défaut
    ok, j'ai compris ce qu'etait une table associative (enfin je crois).
    Ici, ce n'est pas le cas.

    Un utilisateur possede 0 a n preferences.
    Une preference n'est detenu que par un seul utilisateur.

  14. #14
    Candidat au Club
    Inscrit en
    Mars 2010
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Mars 2010
    Messages : 21
    Points : 4
    Points
    4
    Par défaut
    bon, je viens de tester avec un index unique sur les deux champs et ca marche. Mais ca m'embete quand meme de rajouter un index. Ca ne risque pas de ralentir les insertions? Parce que la, ce nouvel index ne me sert que pour assurer l'unicite du couple (user, id). Le trigger me paraissait plus sympa, si il y avait moyen d'annuler l'insertion sous condition...

  15. #15
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    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 799
    Points : 34 046
    Points
    34 046
    Billets dans le blog
    14
    Par défaut
    Les index sont au contraire se qui fait accélérer les requêtes !
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    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 !

  16. #16
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    445
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 445
    Points : 622
    Points
    622
    Par défaut
    Je n'ai pas vraiment compris ce que tu souhaitais faire, et l'utilisation d'un index est probablement une meilleure solution, mais voici quand même un exemple de trigger qui aurait pu faire plus ou moins ce que tu voulais :
    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
     
    DELIMITER $$
     
    USE `OSSITEDB`$$
     
    CREATE TRIGGER `CheckUniqueID`
    BEFORE INSERT ON `PREFERENCE_SETS`
    FOR EACH ROW
    BEGIN
        DECLARE RESULT INT;
    	SET RESULT = (SELECT COUNT(ID)  FROM PREFERENCE_SETS WHERE ID=NEW.ID);
     
    	IF (RESULT<>0) THEN
            SIGNAL sqlstate '45000' SET message_text = 'blah blah';
        END IF; 
    END$$

  17. #17
    Membre expert

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Juin 2012
    Messages
    612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Conseil

    Informations forums :
    Inscription : Juin 2012
    Messages : 612
    Points : 3 066
    Points
    3 066
    Par défaut
    Citation Envoyé par madric Voir le message
    Mais ca m'embete quand meme de rajouter un index. Ca ne risque pas de ralentir les insertions? Parce que la, ce nouvel index ne me sert que pour assurer l'unicite du couple (user, id). Le trigger me paraissait plus sympa, si il y avait moyen d'annuler l'insertion sous condition...
    Ça sera probablement toujours plus rapide qu'un trigger qui va locker la table et faire une requête dessus

  18. #18
    Membre expert
    Avatar de ericd69
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2011
    Messages
    1 919
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2011
    Messages : 1 919
    Points : 3 295
    Points
    3 295
    Billets dans le blog
    1
    Par défaut
    salut,

    les trigger font partis de la transaction (voir le test) même si leur corps est défini aec un begin au début... par contre un begin dans le corps poserait un problème en innodb...


    pour signal dans un trigger ça n'est autorisé que pour mysql 5.1.6

    à tester donc
    soyons pensez à mettre quand votre problème est résolu ou à utiliser pour les réponses pertinentes...
    ne posez pas de problématique soi-disant simplifiée sur des problèmes que vous n'êtes pas capable de résoudre par respect pour ceux qui planchent dessus... sinon: et à utiliser pour insérer votre code...

  19. #19
    Candidat au Club
    Inscrit en
    Mars 2010
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Mars 2010
    Messages : 21
    Points : 4
    Points
    4
    Par défaut
    Un grand merci pour toutes vos reponses. J'ai appris pas mal de choses interessante.

    J'essaye maintenant une autre methode pour arriver a mes fins. Celle que j'ai trouve sur la documentation de MySql ici:

    http://dev.mysql.com/doc/refman/5.0/...ing-reads.html

    Je fais des tests avec la commande "SELECT FOR UPDATE" et bizarrement MySQL me lock la table entierement plutot que de me locker juste la ligne selectionnee. J'utilise le moteur innodb et d'apres la documentation, ca ne devrait pas etre le cas. J'ai vu d'autres personnes sur differents forums soulever le meme probleme, sans trouver aucune explication ou solution. Ca me parait trop gros pour etre un bug. Auriez vous des infos la dessus?

    Merci encore pour toutes vos reponses.

  20. #20
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    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 799
    Points : 34 046
    Points
    34 046
    Billets dans le blog
    14
    Par défaut
    Ca me parait trop gros pour etre un bug.
    Mais MySQL est farci de bugs, de manques, de passoires à problèmes...
    C'est le plus mauvais des "grands" SGBD !
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    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 !

Discussions similaires

  1. Générer un code unique
    Par the watcher dans le forum Langage
    Réponses: 8
    Dernier message: 20/12/2009, 19h09
  2. Réponses: 1
    Dernier message: 17/04/2007, 13h07
  3. Executer une portion de code uniquement si le javascript est actif
    Par Rakken dans le forum Balisage (X)HTML et validation W3C
    Réponses: 3
    Dernier message: 07/04/2007, 10h23
  4. [Sécurité] Vérifier code crypté en md5
    Par vigon dans le forum Langage
    Réponses: 23
    Dernier message: 17/05/2006, 14h32
  5. [VBA-A]suivi d'un code unique d'un formulaire a un autre
    Par acidstrike dans le forum VBA Access
    Réponses: 4
    Dernier message: 09/03/2006, 15h02

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