PDO + beginTransaction pas content - PHP - Programmation
Marsh Posté le 16-10-2015 à 11:09:57
Tu as essayé de forcer l'autocommit à false explicitement (Ne serait-ce que par sécurité) ?
Citation :
Many APIs used for writing MySQL client applications (such as JDBC) provide their own methods for starting transactions that can (and sometimes should) be used instead of sending a START TRANSACTION statement from the client. See Chapter 20, Connectors and APIs, or the documentation for your API, for more information. To disable autocommit mode explicitly, use the following statement: SET autocommit=0; |
https://dev.mysql.com/doc/refman/5.0/en/commit.html
Marsh Posté le 16-10-2015 à 12:46:59
Je suis pas certain de comprendre ce que tu me conseilles de faire, disabler l'autocommit c'est ça ? Et je ferais ça dans phpMyAdmin ? Ou dans mes scripts via PDO ?
Marsh Posté le 16-10-2015 à 14:02:23
Faire
Code :
|
juste avant le beginTransaction
(nb: ne pas oublier de le remettre à 1 après la transaction bien sûr )
Marsh Posté le 16-10-2015 à 15:04:50
Ok, merci. J'ai essayé... Rien n'a changé, même message d'erreur
Marsh Posté le 16-10-2015 à 15:16:57
Et plutôt que de faire une requête UPDATE CASE WHEN, tu as essayé de faire autant de requête UPDATE (toujours au sein d'une même transaction bien sûr) ?
Marsh Posté le 16-10-2015 à 15:20:55
genre comme ça (nb: j'ai rien testé, écris de tête ) :
Code :
|
Marsh Posté le 16-10-2015 à 15:45:44
J'ai modifié un poil le code (en gros j'ai mis des placeholders) :
Code :
|
Et même résultat, même message d'erreur
(NB : j'ai essayé avec et sans entourer le code de $bdd->exec('SET AUTOCOMMIT=0'); et $bdd->exec('SET AUTOCOMMIT=1'); , pas de changement notable)
Marsh Posté le 16-10-2015 à 16:01:06
Tu as une exception sur l'appel à la méthode "rollback". Ca veut dire que tu as déjà eu une erreur dans le scope du "try". Quelle est-elle ? Tu n'affiches ses infos qu'après le rollback, donc tu ne les affiches jamais parce que le rollback pète
Déplace le rollback (juste avant le "exit" ), et met un breakpoint dans le block catch pour voir l'erreur qui survient avant. Cela nous donnera peut-être des indices !
Marsh Posté le 17-10-2015 à 18:34:35
Alors du coup en fait j'ai dû manquer d'attention quand je faisais mes tests, parce que mon problème existe toujours, même sans la transaction : quand je suis sous les 72 éléments, ça update, et au dessus, non...
Connais pas les breakpoints, comment ça fonctionne ? Comme ça ? :
Code :
|
(Ca a pas l'air) :
Code :
|
Marsh Posté le 17-10-2015 à 19:10:44
Oublie le breakpoint.
L'erreur sans transaction, elle dit quoi ?
Normalement, avec une requête par modification (comme j'ai montré plus haut), ça devrait fonctionner
Marsh Posté le 17-10-2015 à 21:07:49
kao98 a écrit : Oublie le breakpoint. |
Ah oui désolé : ça me donne aucune erreur, ça se contente simplement ne pas updater. D'où l'ajout du bloc
Code :
|
qui est mon seul moyen de voir si l'update a effectivement été effectuée (l'echo 'bloc try ok' apparaît à chaque fois, que l'update ait effectivement lieu ou non). Quand j'ai plus de 73 éléments, la ligne n'apparaît plus.
Citation :
|
Tu parles de ça j'imagine.
kao98 a écrit :
|
J'essaie demain et je te dis.
Mais c'est pas très efficace d'assaillir ma bdd de requêtes, non ? (On m'a dit que c'était à éviter à tout prix)
Marsh Posté le 17-10-2015 à 21:40:27
saint malo a écrit :
|
Ajoute quelque chose comme ça :
Code :
|
ca va renvoyer l'erreur qui se produit à ce moment là.
Marsh Posté le 19-10-2015 à 11:52:30
Alors.
1) Avec ma grosse requête unique UPDATE CASE WHEN
Code : |
Me donne :
Code :
|
2) La même chose avec une requête UPDATE différente pour chaque élément me donne la ligne "execute ok" autant de fois que d'éléments à updater... et pourtant la table n'est pas updatée ! Du coup j'ai modifié le code comme ça :
Code : |
Et là, j'ai ça autant de fois que d'éléments à updater :
Code :
|
(De ce que je lis de l'erreur "MySQL server has gone away", ça veut juste dire que j'essaie d'updater trop de choses à la fois et qu'il me reste que mes yeux pour pleurer..., c'est ça ?)
Marsh Posté le 19-10-2015 à 14:09:14
Ok donc en fait, il s'agit juste d'un timeout de MySql (en fait, je pense que ça vient plutôt du driver php mysql)
Jettes un oeuil là : http://stackoverflow.com/questions [...] 60-seconds
Marsh Posté le 19-10-2015 à 15:42:45
Par hasard, ton appli web ne serait pas hébergée chez OVH Parce que ton pb m'en rappelle un que j'ai eu avec eux pour une appli qui faisait pas mal d'accès à la BD. Du coup, il valait mieux faire un seul accès un peu gros plutôt que de nombreux petits accès à la BD.
Marsh Posté le 19-10-2015 à 15:47:45
rufo a écrit : Par hasard, ton appli web ne serait pas hébergée chez OVH Parce que ton pb m'en rappelle un que j'ai eu avec eux pour une appli qui faisait pas mal d'accès à la BD. Du coup, il valait mieux faire un seul accès un peu gros plutôt que de nombreux petits accès à la BD. |
C'est ce qu'il faisait initialement, un gros accès.
Je lui ai proposé de faire plein de petits accès, mais le problème est encore là il semblerait.
Marsh Posté le 19-10-2015 à 17:00:22
Je sais pas si j'ai fait ce qu'il fallait, mais j'ai ajouté ces deux lignes :
Code : |
juste après la connexion à la bdd. C'est bien ce qu'il fallait faire ?
Et aucun changement notable
(Je ne suis pas chez OVH mais chez hostinger )
Marsh Posté le 19-10-2015 à 17:02:39
saint malo a écrit : Je sais pas si j'ai fait ce qu'il fallait, mais j'ai ajouté ces deux lignes :
juste après la connexion à la bdd. C'est bien ce qu'il fallait faire ? |
Il faut les mettre juste avant la connexion. Tout au début du script.
Mais si tu es sur un hébergeur mutualisé, ça ne changera sans doute rien.
Il faut découper le travail et le répartir dans le temps, à travers plusieurs requêtes.
Marsh Posté le 19-10-2015 à 17:08:28
hostinger, c'est du mutualisé, le pb est très probablement le même que chez OVH. Comme indiqué, il va falloir "ruser" en faisant en sorte que ton script limite le nb de requêtes SQL à la BD et son temps de connexion à cette dernière
Marsh Posté le 19-10-2015 à 17:28:30
En effet, ça change rien. C'est dingue quand même, 72 lignes updatées ça me parait peu, non ?
Du coup, comment je fais ça ? En updatant par paquets de 72 (vu qu'apparemment c'est la limite) et en mettant des sleep() ?
J'ai un moyen d'avoir des infos sur les limites sur le nombre de requêtes et sur le temps de connexion, histoire d'optimiser et me mettre juste en dessous de ces limites ?
Marsh Posté le 19-10-2015 à 17:35:46
Les sleep() ne changeront rien à mon avis car les limites de connexion/requêtes à la BD doivent probablement être associées au nom du script en cours d'exécution.
Si t'as moyen, fait le update via le cron par paquets de qq enregistrements
Moi, sur la page où ça me posait le plus de pb (un gros tableau de type formulaire avec pleins de cases à cocher), j'avais résolu le pb avec de l'ajax. Plutôt que de mettre à jour la BD sur le post du formulaire et donc pleins de cases à cocher à traiter ce qui faisait planter le script à cause de la limitation d'OVH, je mettais la BD à jour à chaque fois qu'une case était cochée/décochée avec une requête ajax. Du coup, plus besoin de poster le gros formulaire
Marsh Posté le 19-10-2015 à 21:38:26
saint malo a écrit : En effet, ça change rien. C'est dingue quand même, 72 lignes updatées ça me parait peu, non ? |
72 updates ça paraît peut effectivement.
Ta table est correctement optimisée (des index existent ? Sur les bons champs ?) ?
Marsh Posté le 20-10-2015 à 11:24:35
Citation : Si t'as moyen, fait le update via le cron par paquets de qq enregistrements |
Ben du coup c'est ce que je fais, mais par paquets de 72 maximum...
Citation : Ta table est correctement optimisée (des index existent ? Sur les bons champs ?) ? |
Honnêtement je saurais pas vraiment dire, SQL et moi ça fait pas deux...
J'ai essayé de limiter au maximum le nombre d'index parce que je me sens pas à l'aise avec, donc j'ai qu'un PRIMARY et un UNIQUE : ma table a 34 colonnes, dont :
- la colonne id : UNSIGNED MEDIUMINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
- 2 autres colonnes d'id pour faire la jointure avec deux autres tables (genre categorie_id et auteur_id) : UNSIGNED MEDIUMINT NOT NULL,
- 19 colonnes contenant des données numériques : UNSIGNED MEDIUMINT NOT NULL,
- 7 colonnes qui me permettent de savoir quand certaines des données numériques ont été updatées pour la dernière fois DATETIME NOT NULL,
- 1 colonne BOOLEAN NOT NULL,
- 3 colonnes TEXT NOT NULL,
- et une colonne VARCHAR(255) NOT NULL UNIQUE
Si vous avez des conseils sur des modifs à apporter, je suis preneur
Marsh Posté le 21-10-2015 à 10:57:24
En faisant une autre requête simple ça marche ? T'es sûr des paramètres des connexions BDD ?
Marsh Posté le 21-10-2015 à 17:11:28
Pablo Escrobarbe a écrit : En faisant une autre requête simple ça marche ? T'es sûr des paramètres des connexions BDD ? |
C'est gentil de vouloir aidé, mais ce serait bien de lire le sujet avant
Marsh Posté le 21-10-2015 à 18:49:14
Hehe oui, j'étais pas sur de comment répondre ^^
Pablo Escrobarbe a écrit : En faisant une autre requête simple ça marche ? T'es sûr des paramètres des connexions BDD ? |
Mais peut être que tu veux dire une requête autre qu'un update ? Pas dans ce script là, mais j'ai d'autres endroits de mon appli où j'ai des requêtes insert, et elles fonctionnent. Mais bon, j'insert jamais plus de 72 éléments d'un coup, donc je peux pas vraiment te dire si ça ça fonctionne.
Par paramètres de connexion BDD, tu entends quoi ? Si tu entends ce qui est là dedans :
Code :
|
la réponse est que ça se connecte bien et n'a aucun souci à faire les select, insert, etc, et les update de moins de 73 éléments du coup donc à priori, ça va
Après si tu parles d'autre chose avec "paramètres de connexion BDD", je sais pas de quoi il est question et je veux bien des précisions.
Marsh Posté le 23-10-2015 à 15:20:49
saint malo a écrit : Si vous avez des conseils sur des modifs à apporter, je suis preneur |
Pas d'idées ?
En tout cas merci pour l'aide jusqu'ici
Marsh Posté le 15-10-2015 à 12:26:58
Alors pour commencer : ma question concerne à la fois PDO et du SQL, donc je ne suis peut être pas dans la bonne sous catégorie, mais je pense que ça correspond plus à PHP qu'à SQL/NoSQL. Désolé si je me trompe, n'hésitez pas à déplacer
Ensuite, ce que j'utilise : MySQL, PDO, et ma table utilise InnoDB.
J'ai essayé d'obtenir des réponses sur stackoverflow, mais les personnes qui ont essayé de m'aider ont calé.
Tout d'abord, mon code :
Autrement dit, ça donne ça :
- Je me connecte à la BDD
- Je construis une requête qui ressemble à ça :
- Je peux régler le nombre de lignes que j'essaie d'updater en modifiant mon array $elements
- Je prepare() la requête
- J'ouvre une transaction
- J'essaie de faire l'update et de commit, et si ça marche pas je rollback et j'affiche un message d'erreur.
Seulement voilà, après avoir testé, il se trouve que :
- Cas A) si le nombre d'éléments dans $elements est de 72 ou moins, ça marche très bien, l'update se fait, ça commit, pas de souci.
- Cas B) en revanche si le nombre d'éléments est de 73 ou plus, l'update ne se produit pas, et j'ai le message d'erreur suivant :
La ligne 106 étant $bdd->rollback();
Dans ce cas là (le cas B, avec 73+ éléments), j'ai tenté plusieurs choses :
a) J'ai fait des tests pour voir si c'est la longueur de la requête (en nombre de caractères) qui posait problème, je vous passe les détails mais je suis à peu près certain que ça n'est pas ça qui pose problème.
b) vardump($bdd->beginTransaction(); ) me donne bool(false) dans le cas B (ça me donne bool(true) dans le cas A)
c) J'ai copié/collé la requête construite dans le cas B directement dans phpMyAdmin, ça update sans problème
d) Et de même dans mon script, si je me débarrasse des lignes qui concernant la transaction : beginTransaction(), commit() et rollback(), je n'ai plus d'erreur et l'update se produit sans problème. Donc je ne pense pas que ce soit le contenu de ma requête qui soit la source du problème.
Voila. Si vous avez une idée de choses à tenter et/ou de ce qui ne tourne pas rond, je vous en serais fort reconnaissant. Merci !
Message édité par saint malo le 16-10-2015 à 12:50:30