6
votes

Comment un objet PHP PDO peut-il déterminer s'il est déjà dans une transaction MySQL?

J'ai deux objets PHP compliqués, chacun ayant des données dans quelques tables MySQL.

Parfois, il suffit de supprimer un objet A de la base de données, ce qui prend 3 déclarations SQL. P> Parfois, je dois supprimer un objet B de la base de données, qui prend 4 déclarations SQL et que également strud> a besoin de trouver et de supprimer tout l'objet A de l'objet B possède. P >

donc à l'intérieur de la fonction Supprimer_a (), j'exécute ces déclarations à l'intérieur d'une transaction. À l'intérieur de la fonction Delete_B (), je souhaite exécuter une grande grande transaction qui couvre les activités à l'intérieur de Delete_A (). Si tout l'atome d'atome de suppression d'un B échoue, je dois restaurer tous ses A dans le rollback. P>

Comment mettre à jour la définition de suppression_a () pour ouvrir une nouvelle transaction si Il n'y a pas déjà une opération de transaction plus grosse. P>

Je m'attendais à pouvoir faire quelque chose comme ça, mais l'attribut autocommit code> ne semble pas être modifié par Begintransaction () Code> P>

function delete_A($a){
  global $pdo;
  $already_in_transaction = !$pdo->getAttribute(PDO::ATTR_AUTOCOMMIT);
  if(!$already_in_transaction){
    $pdo->beginTransaction();
  }

  //Delete the A

  if(!$already_in_transaction){
    $pdo->commit();
  }
}
function delete_B($b){
  global $pdo;
  $pdo->beginTransaction();
  foreach($list_of_As as $a){
    delete_A($a);
  }
  $pdo->commit();
}


1 commentaires

Vous voudrez peut-être envisager d'utiliser des contraintes de clé étrangère (des moyens devront passer de Myisam à un moteur qui les prend en charge) - De cette façon, vous pouvez faire en sorte que les dB ne soient en cascade pour vous au lieu de les émuler.


3 Réponses :


1
votes

Un moyen est de créer votre propre classe PDoconnect, qui a une variable HASTransaction . Ensuite, vous venez de vérifier cela. Un exemple peut être trouvé sur les commentaires de la fonction de begintransaction sur php.net ici ici http://www.php.net/manual/fr/pdo.begintransaction.php#81022

Ce serait ma préférence. Accordé cet exemple aura besoin de peaufiner et de s'habiller, etc., mais devrait être une bonne fondation à partir de.

Note latérale N'oubliez pas que votre table doit être innodb pour que les transactions fonctionnent. Et puisque vous devez être à Innodb pour que les transactions au travail, vous devriez prendre les conseils de Prodigitaux et utiliser des contraintes de clé étrangère.


0 commentaires

9
votes

PDO :: ATTRE_AUTOCOMMIT n'est pas un attribut indicateur, c'est un attribut de contrôle. Il contrôle si les déclarations SQL s'engagent implicitement quand elles se terminent.

Vous pouvez appeler pdo :: intransaction () qui retourne 0 si vous n'avez aucune transaction en cours et 1 si vous avez un transaction en circulation qui doit être commise ou roulée. Cependant, cette fonction n'est pas documentée, il est donc difficile de dire s'il est prudent de dépendre de celui-ci dans toutes les versions futures de PDO.

Je recommande que les développeurs PHP n'essayent pas de gérer les transactions dans la fonction de fonction ou de la classe. Vous devez gérer les transactions au niveau supérieur de l'application.

Voir aussi:


2 commentaires

Merci pour les liens, cela m'a conduit à la solution que j'ai fini par utiliser.


intransaction () est maintenant documentée. php.net/manual/fr/pdo.intransaction.php



2
votes

J'ai fini simplement en utilisant l'exception projetée par -> Begintransaction () Pour déterminer si j'étais dans une transaction et que j'utilise cela pour décider de commettre la boucle intérieure. Donc Supprimer_a () a fini par apparaître comme: xxx

et delete_b () fonctionne sans modification.


1 commentaires

Et si cela est appelé par une autre routine qui a commencé la transaction et décide de retirer? Votre Supprimer sera annulée.