2010-11-24 9 views
14

EDIT: À l'origine, le titre de cette question était: Comment est-ce que Doctrine connaît le dernier identifiant inséré dans MySQL? et a été liée à Doctrine ORM mapper. Après quelques fouilles j'ai découvert que cette question n'est pas liée à Doctrine mais à PDO_MySQL, MySQL C API et enfin - à la communication client-serveur MySQL. J'ai décidé de changer le titre, alors peut-être que quelqu'un trouvera une réponse à sa question.Comment PDO connaît-il le dernier identifiant inséré dans MySQL?

Pour ceux qui n'utilisent pas Doctrine: J'étais curieux, pourquoi ci-dessous:

mysql_query("INSERT INTO category (name) VALUES('cat')"); 
echo mysql_insert_id(); 

ou similaire:

$pdo->exec("INSERT INTO category (name) VALUES('cat')"); 
echo $pdo->lastInsertId(); 

conduira à une seule position (sans SELECT LAST_INSERT_ID() séparée) dans le journal:

1701 Query INSERT INTO category (name) VALUES ('cat') 

question d'origine:

J'ai 2 tables:

category(id,name) 
product(id, name, categoryId) 

J'ai créé nouvel objet de la catégorie et de l'objet produit. J'ai affecté l'objet catégorie à l'objet du produit. Je ne l'ai pas mis les ids:

$product = new Product(); 
$product->name = 'asdf'; 

$category = new Category(); 
$category->name = 'cat'; 

$product->Category = $category; 

Après que je rougis la connexion et vérifier les journaux MySQL:

1684 Query START TRANSACTION 
1684 Query INSERT INTO category (name) VALUES ('cat') 
1684 Query INSERT INTO product (name, categoryid) VALUES ('asdf', '312') 
1684 Query COMMIT 

Comment savoir Doctrine, que l'identifiant de la catégorie nouvellement créée est 312? Il n'y a rien d'autre dans les journaux.

Répondre

22

J'ai fait quelques recherches et parcourir un code source, donc ma réponse pourrait être un peu mal et pas précis. Tout d'abord, ce n'est pas vraiment lié à Doctrine. Doctrine utilise PDO_MYSQL. Mais en interne PDO_MYSQL utilise la même chose que mysql_insert_id fonction - native MySQL C API fonction - mysql_insert_id.

La raison pour laquelle il n'y a pas séparés SELECT LAST_INSERT_ID() réside dans le fait que, après l'instruction est exécutée (dans mon exemple INSERT), serveur répond avec des données et d'autres choses incluses dans Packet) OK, y compris insert_id. Donc, quand nous tirons mysql_insert_id() nous ne sommes pas connectés au serveur, pour recevoir insert_id - la bibliothèque mysql n'a pas besoin de faire cela - il a déjà cette valeur stockée à partir de la dernière exécution de requête (au moins je le pense après l'analyse du fichier libmysql.c)

Packet OK est décrit ici: MySQL Generic Response Packets - OK Packet

+0

Grande recherche. – jensgram

+0

C'est pourquoi nous pouvons l'utiliser, sans crainte de course de requête. Je vous remercie. – noober

1
+0

Mais cela serait reflété dans le journal, ne serait-il? –

+0

@Pekka Une conjecture non éduquée: Le journal peut-il être configuré pour * ne pas * écrire "SELECT"? – jensgram

+0

@jensgram pourrait être - ou il pourrait être configuré pour afficher les résultats des appels de fonction (à savoir 'LAST_INSERT_ID()'). Je ne sais pas comment les journaux de requêtes fonctionnent –

1

last_insert_id ne fonctionne que pour AUTO_INCREMENT colonnes. Cela ne fonctionnera pas si vous insérez manuellement une valeur dans la colonne AUTO_INCREMENT.

La doctrine fonctionnera car elle équivaut à lui attribuer un NULL (bien que vous n'écriviez jamais spécifiquement cela). Ceci déclenche l'incrément automatique et fournit une valeur pour last_insert_id().

J'ai inclus un jpg ici pour que vous puissiez le voir. J'espère que cela aide!

enter image description here

+0

Cela n'explique pas comment la doctrine récupère effectivement la valeur bien. Aucune requête ne récupère last_insert_id. – ryeguy

+0

Cette réponse n'est pas liée à la question. – prostynick

Questions connexes