J'ai besoin de verrouiller une table entière (pas une seule rangée) avec la doctrine, je voudrais le faire sans requêtes natales si possible. P>
La documentation de Le verrouillage pessimiste ne décrit que comment verrouiller des entités spécifiques via ces méthodes: P>
J'ai une transaction qui doit insérer une ligne dont les valeurs dépendent des valeurs du reste des lignes de la table, de sorte que je dois empêcher deux transactions effectuant en même temps sur cette table. P>
J'utilise une démarcation de transaction explicite, qui est censée bien fonctionner avec le verrouillage (selon la documentation ci-dessus). P>
EDIT STRUT>: Je vais donner un exemple. Imaginez que vous souhaitiez construire un auto_incrènement, et vous devez sélectionner Max () à partir de la table pour obtenir le résultat précédent afin d'insérer le prochain. Vous devez vous assurer que les deux transactions n'essaient pas d'insérer la même valeur au cas où elles sélectionneront max () en même temps. P>
Je cherche une solution générale à ce problème lorsque vous n'êtes pas bon, par exemple avec des chaînes, ou plusieurs colonnes, hachages ou quel que soit le calcul que vous devez faire sur le jeu de lignes précédent. P>
Le verrouillage est une solution solide et, contrairement au verrouillage optimiste, vous n'avez pas à réessayer sur des erreurs. P>
Alors, y a-t-il un moyen d'utiliser le verrouillage de table dans la doctrine? P>
3 Réponses :
En regardant la documentation dans la doctrine 2.x, je ne pense pas qu'il existe une manière prise en charge de verrouiller toute la table. Vous pouvez bien sûr essayer de verrouiller tous les enregistrements via la doctrine individuellement, mais ce serait lourd et n'est pas vraiment une bonne idée. P>
Au lieu de cela, j'utiliserais la doctrine Entity Manager pour exécuter SQL brut sur la base de données ... P>
et ensuite après que vous ayez terminé avec votre mise à jour ... p>
EDIT: P>
de Documentation MySQL sur les serrures de table .. . P>
la session qui contient la serrure peut lire et écrire la table. p> li>
Seule la session qui détient la serrure peut accéder à la table. Aucune autre session ne peut y accéder jusqu'à ce que la serrure soit libérée. P> li>
Les requêtes de verrouillage de la table par d'autres sessions Block tandis que le verrouillage de l'écriture est maintenu. p> li>
ul>
blockQuote>
Je pense que le deuxième point ici est essentiel, seule votre session peut lire / écrire à cette table. P> $ em-> getconnection () -> exec ("tables de verrouillage table_name écriture; '); // Verrouiller l'accès en écriture code> p>
$ em-> getconnection () -> exec ('déverrouillage des tables;'); code> p>
En outre, le verrouillage individuellement les enregistrements n'empêcherait pas de nouveaux enregistrements beign insérés. OTOH L'instruction de verrouillage n'est pas transactionnelle selon la DOCS, et je ne sais pas comment la doctrine implémente les transactions, mais si elle utilise la transaction de démarrage, cela ne fonctionnera pas.
Tables de verrouillage [Nom_Tbl_Name] code> verrouille toute la table pour écrire, voir mon édition
Oui, je sais, le seul problème que j'ai avec serrure est qu'il ne joue que lorsque vous effectuez des transactions à l'aide de «Autocommit = 0 ', et je ne sais pas comment la doctrine gère les transactions. Je dois encore le tester. Voir cette dev.mysql.com/doc/ Refman / 5.0 / FR / ...
La doctrine vous oblige à envelopper les appels dans une transaction explicite, et même alors c'est difficile (impossible?) Parce que la doctrine utilise parfois des alias dans ses mises à jour SQL ("Si vos déclarations font référence à une table au moyen d'un alias, vous devez verrouiller la table en utilisant ce même alias "). Dans ma situation, il utilise un alias et le nom de la table dans la seule transaction.
éventuellement dupliqué par Doctrine2 Orm Sélectionner pour la mise à jour
Voici quelques indicateurs connexes : p> Le paramètre LockMode :: optimiste peut fournir ce dont vous avez besoin. p> p>
En général, la sélection de la ligne de mise à jour n'empêche pas d'inserts simultanés.
Suivre les conseils jusqu'à présent, j'ai essayé ceci:
$em->getConnection()->exec('LOCK TABLES table_name WRITE;'); //lock for write access // calculate $new_number... // persist $new_number on table_name... $em->getConnection()->executeUpdate("UPDATE table_name set ...;"); $em->getConnection()->exec('UNLOCK TABLES;'); $em->refresh($table_name);
IMO, une meilleure option serait d'ouvrir une transaction, de récupérer les données de la table dont vous avez besoin via une requête SELECT, puis effectuez la mise à jour.
Le problème est que si une seconde transaction vient avant la première validation de la deuxième transaction insérerait une valeur non valide. Le résultat de la deuxième transaction doit dépendre de la ligne insérée par le premier. C'est pourquoi j'ai besoin de verrouillage, les transactions ne doivent pas se chevaucher pour cette table.