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 :

mysqli_insert_id est-il vraiment fiable ?


Sujet :

MySQL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Webmaster
    Inscrit en
    Janvier 2016
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Janvier 2016
    Messages : 12
    Par défaut mysqli_insert_id est-il vraiment fiable ?
    Bonjour,

    J'ai une table avec un auto incrémente. J'ai besoin de savoir avec absolu certitude l'auto incrémente généré par mon insert, voici ce que je fait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    étape 1 : mysqli_query($mysqli,$requete_avec_insert); // enregistrer
    étape 2 : $id_de_la_ligne=mysqli_insert_id($mysqli); // récupérer le dernier auto incrémente crée
    Les lignes se suivent comme ca dans le code, il n'y a rien entre.

    La question que je me pose, et qui peut être est bête je ne sais pas , qu'est ce qui se passe si à la milliseconde prêt un autre visiteur insère une ligne entre l'étape 1 et l'étape 2 ? Suis certain à 100 % que j'ai bien récupérer le bon id ?

  2. #2
    Membre prolifique Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 897
    Par défaut
    Salut Zachatim.

    Citation Envoyé par Zachatim
    mysqli_insert_id est-il vraiment fiable ?
    En voilà une question ??? Bien sûr que cela fonctionne correctement, mais faudrait encore savoir s'en servir correctement.

    1) ici, nous sommes dans le forum consacré à MySql et non à php.

    2) l'équivalent de l'instruction php "mysqli_insert_id()", ci-après :
    --> http://php.net/manual/fr/mysqli.insert-id.php
    est la fonction mysql "last_insert_id()"
    --> http://dev.mysql.com/doc/refman/5.7/...last-insert-id

    3) si vous désirez récupérer l'identifiant de la dernière insertion, vous devez au préalable faire une et une seule insertion.
    Donc pas d'insert multiple !

    Citation Envoyé par Zachatim
    qu'est ce qui se passe si à la milliseconde prêt un autre visiteur insère une ligne entre l'étape 1 et l'étape 2 ?
    Et bien, vous êtes dans la merde !

    4) Pour résoudre ce genre de problème, vous devez utiliser vos tables avec le moteur "InnoDB", et utiliser le mode transactionel.
    --> http://dev.mysql.com/doc/refman/5.7/en/commit.html
    Le mode transactionel ne fonctionne qu'avec le moteur "InnoDB" et non avec "MyIsam".

    5) Vous devez déclarer dans le fichier my.ini, la directive suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    transaction-isolation = SERIALIZABLE
    --> https://dev.mysql.com/doc/refman/5.6...ansaction.html

    6) que dois-je faire en php ?
    Le mieux serait de vous adresser au forum consacré à php et à mysql.
    Sinon, voici quelques pistes à suivre en php (§7, §8, §9 et §10).

    7) désactiver le mode autocommit :
    --> http://php.net/manual/fr/mysqli.autocommit.php

    8) et ensuite ?
    Démarrer le mode transactionel :
    --> http://php.net/manual/fr/mysqli.begin-transaction.php

    9) et puis ?
    Et bien vous faites votre insert, et vous récupérez votre dernier identifiant insérée dans la table.

    10) et après ?
    Et bien, si vous êtes satisfait de votre insert, vous validez :
    --> http://php.net/manual/fr/mysqli.commit.php
    ou vous rejetez ce que vous venez de faire :
    --> http://php.net/manual/fr/mysqli.rollback.php

    11) voici un exemple, mais en MySql :
    --> http://stackoverflow.com/questions/2...tions-examples

    @+

  3. #3
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Par défaut
    Citation Envoyé par Artemus24 Voir le message

    Et bien, vous êtes dans la merde !

    4) Pour résoudre ce genre de problème, vous devez utiliser vos tables avec le moteur "InnoDB", et utiliser le mode transactionel.
    êtes vous sûr de ce que vous dites ?
    Dans la doc dont vous mettez le lien juste au dessus, on peut lire ceci :


    Citation Envoyé par doc MySQL
    The ID that was generated is maintained in the server on a per-connection basis. This means that the value returned by the function to a given client is the first AUTO_INCREMENT value generated for most recent statement affecting an AUTO_INCREMENT column by that client. This value cannot be affected by other clients, even if they generate AUTO_INCREMENT values of their own. This behavior ensures that each client can retrieve its own ID without concern for the activity of other clients, and without the need for locks or transactions.
    A mon sens, cela dépend donc de la façon dont Zachatim gère ses connexions

  4. #4
    Membre averti
    Homme Profil pro
    Webmaster
    Inscrit en
    Janvier 2016
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Janvier 2016
    Messages : 12
    Par défaut
    Merci pour vos réponses.

    J'ai lu la réponse de Artemus24 avec attention, et parcouru la doc.
    J'ai appris quelque chose au passage ! En cela je vous remercie.

    Cependant, le mode transactionnel ne semble pas répondre à ma problématique.
    J'ai compris que je pourrais rollback mon insert en cas de problème, mais je ne peut pas savoir si mysqli_insert_id() (last_insert_id() en mysql) m'a bel et bien donné le bon ID.
    En effet a priori il va me donner un ID, mais est-ce bien celui que je viens d'insérer ou bien celui d'un autre visiteur de la même page qui l'affiche exactement en même temps ?

    aieeeuuuuu >"
    A mon sens, cela dépend donc de la façon dont Zachatim gère ses connexions
    "
    Pouvez-vous donner plus de précision sur ce que je ne dois pas faire ?

    Je peux donner plus de code si besoin, mais dois-je le faire sur le forum php ou mysql :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    $mysqli = mysqli_connect($hostname, $username, $password, "table"); // connec
    mysqli_set_charset($mysqli, "utf8");
    mysqli_query($mysqli,"INSERT INTO message(id,texte) VALUES('','$texte')"); // la variable ID est en auto incrémente
    $id_de_la_ligne=mysqli_insert_id($mysqli); // je vais chercher le dernier auto incrémente
    mysqli_close($mysqli); // j'ai récupérer mon id, je n'ai plus besoin de mysql pour la suite du traitement
    En résumer j'essais de comprendre si mysqli_insert_id() en php qui correspond donc à un last_insert_id() va chercher l'info pour la globalité de la table ou s'il est " cloisoné " .

  5. #5
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Par défaut
    Citation Envoyé par Zachatim Voir le message
    Pouvez-vous donner plus de précision sur ce que je ne dois pas faire ?
    Je ne peux vous répondre avec certitude, n'utilisant ni php ni MySQL...

    Mais d'après la doc, cette fonction est limitée à la connexion. Comme visiblement vous gérez votre connexion par script, si un utilisateur concurrent effectue une insertion, cela ne devrait pas poser de problème (se serait sans doute une autre histoire si votre connexion était partagée)

    Cependant, le mieux est de tester :
    Faites un script A qui fait une insertion, fait une pause de quelques secondes, puis récupère l'ID inseré.
    Faites un script B qui fait la même chose sans la pause, et lancez-le pendant la pause du premier
    Voyez le résultat (et venez nous en faire part ! )

  6. #6
    Membre averti
    Homme Profil pro
    Webmaster
    Inscrit en
    Janvier 2016
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Janvier 2016
    Messages : 12
    Par défaut
    Bon je viens de faire le test avec la fonction sleep() de php .
    J'ai mis un sleep à 10 secondes et l'autre page sans sleep j'ai fait des F5.

    Les valeur des auto incrémente sont cohérent avec ce qu'il devrait être, le script avec la pause à son propre auto incrémente qui semble être isolé de l'autre script sans pause.
    A priori donc ce que dit la doc
    This value cannot be affected by other clients
    se vérifie.

  7. #7
    Membre prolifique Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 897
    Par défaut
    Salut Zachatim.

    Citation Envoyé par Zachatim
    Cependant, le mode transactionnel ne semble pas répondre à ma problématique.
    Le mode transactionel répond normalement à votre demande.
    A partir du moment où vous faites un "start transaction", vous bloquez tout le monde.
    De ce fait, vous serez le seul à pouvoir insérer dans la base de données. Les autres demandes sont mis en attente.
    De ce fait, vous travaillez dans votre base de données, comme si vous étiez seul !
    Il est impératif de redonner la main le plus rapidement, en faisant soit un commit, soit un rollback, afin de ne pas bloquer tout le monde.

    J'ai oublié de vous poser la question ; quel est le moteur de votre base de données ?
    Est-ce InnoDB ou MyIsam ?

    Citation Envoyé par Zachatim
    je ne peux pas savoir si mysqli_insert_id() (last_insert_id() en mysql) m'a bel et bien donné le bon ID.
    Une possibilité pour vérifier si vous avez bien la bonne ligne, est de faire une extraction et de comparer les valeurs de chaque colonne.
    Vous aurez ainsi la certitude d'avoir la ligne que vous venez d'insérer précédemment. Sauf que cette approche est lourde, voire sans intérêt.

    Citation Envoyé par Zachatim
    En effet a priori il va me donner un ID, mais est-ce bien celui que je viens d'insérer ou bien celui d'un autre visiteur de la même page qui l'affiche exactement en même temps ?
    C'est pourquoi, je vous ai parlé du mode transactionnel !

    J'ai fait une recherche afin de comprendre la particularité de ce "mysqli_insert_id()".
    J'ai trouvé un lien où il est expliqué votre problème :
    --> http://stackoverflow.com/questions/2...sqli-insert-id

    Si l'on se concentre uniquement sur la fonction "mysqli_insert_id()", il vous retournera le dernier identifiant :
    1) juste après que vous ayez fait un insert (ou un update).
    Dans le cas contraire, à savoir pas de colonne auto incrémentée, ou sur un select, il vous retournera zéro.

    2) il est conditionné par votre connexion.
    Cela signifie que vous ne récupérerez pas l'identifiant d'un autre utilisateur, qui ce serait intercalé entre votre insert et la récupération du dernier identifiant.

    3) la dernière valeur insérée dans la table, est produite par l'auto incrément de cette même table.
    Comme mysql est multiutilisateur, on ne peut pas récupérer cette valeur en faisant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT AUTO_INCREMENT as last_id
    FROM   INFORMATION_SCHEMA.TABLES
    WHERE  table_schema = 'base' and table_name = 'test';
    car notre dernière insertion n'est pas nécessairement la dernière insertion dans la table.

    Je comprends mieux pourquoi la connexion conserve la dernière valeur de l'identifiant auto incrémenté.
    Car sans cela, et sans le mode transactionnel, il est impossible de la récupérer.

    4) il existe une autre solution, qui consiste à gérer par vous-même les identifiants.

    Je pense que le §2 est la réponse donnée par aieeeuuuuu.

    Citation Envoyé par aieeeuuuuu
    êtes vous sûr de ce que vous dites ?
    Je ne suis jamais certain de quoi que ce soit.

    Si j'utilise justement le mode transactionnel, c'est pour éviter les conflits de ce genre.

    @+

  8. #8
    Membre émérite Avatar de Oishiiii
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2009
    Messages
    508
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Ain (Rhône Alpes)

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

    Informations forums :
    Inscription : Août 2009
    Messages : 508
    Par défaut
    Citation Envoyé par Artemus24 Voir le message
    A partir du moment où vous faites un "start transaction", vous bloquez tout le monde.
    De ce fait, vous serez le seul à pouvoir insérer dans la base de données. Les autres demandes sont mis en attente.
    De ce fait, vous travaillez dans votre base de données, comme si vous étiez seul !
    Il est impératif de redonner la main le plus rapidement, en faisant soit un commit, soit un rollback, afin de ne pas bloquer tout le monde.
    Vraiment ?

  9. #9
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    22 002
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 22 002
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par Artemus24 Voir le message
    A partir du moment où vous faites un "start transaction", vous bloquez tout le monde.
    De ce fait, vous serez le seul à pouvoir insérer dans la base de données. Les autres demandes sont mis en attente.
    De ce fait, vous travaillez dans votre base de données, comme si vous étiez seul !
    Il est impératif de redonner la main le plus rapidement, en faisant soit un commit, soit un rollback, afin de ne pas bloquer tout le monde.
    C'est du grand n'importe quoi !!!! À moins que MySQL soit véritablement un outil pour crétins, je ne pense pas qu'une transaction démarrée en mode sérializable bloque quoi que ce soit, tant que, dans la session invoquant le mode d'isolation SERIALIZABLE :
    • aucune lecture n'a été effectuée
    • aucune modification n'a été réellement entreprise
    • aucune autre table que les tables modifiées (bloquées en totalité)
    Et même une simple lecture de la table n'est en principe même pas bloquante pour les autres utilisateurs qui veulent lire
    Et à fortiori, aucun blocage n'a lieu sur les autres tables...

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 18/12/2006, 08h39
  2. [Reference][String][Integer] Qu'est ce vraiment ?
    Par ZeKiD dans le forum Langage
    Réponses: 17
    Dernier message: 24/01/2006, 17h22
  3. [AJAX] est-ce que c'est bien et fiable
    Par hansaplast dans le forum Général JavaScript
    Réponses: 14
    Dernier message: 18/11/2005, 14h44
  4. Réponses: 9
    Dernier message: 12/12/2004, 11h55

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