web-dev-qa-db-fra.com

Les transactions MySQL dans les transactions

Dans A PHP Script fonctionnant avec une base de données MySQL, j'ai récemment eu la nécessité d'utiliser une transaction à un point qui se trouve être à l'intérieur d'une autre transaction. Tous mes tests semblent indiquer que cela fonctionne bien , mais je ne trouve aucune documentation sur cette utilisation.

Je veux être sûr - sont des transactions dans les transactions valables dans MySQL? Si tel est le cas, est-il un moyen de savoir combien de niveaux vous approfondis dans des transactions imbriquées? (c.-à-d. Combien de rentachements qu'il faudrait pour revenir à la normale)

Merci d'avance, Brian

49
Brian

Cette page du manuel pourrait vous intéresser: ( 12.3.3. Des déclarations qui provoquent une commission implicite ; citant quelques phrases:

Les déclarations énumérées dans cette section (et tous les synonymes pour eux) mettent implicitement terminer une transaction, comme si vous aviez fait un COMMIT avant d'exécuter la déclaration.

Et un peu plus loin dans la page:

Déclarations de contrôle des transactions et de verrouillage. BEGIN, LOCK TABLES, SET autocommit = 1 (si la valeur n'est pas déjà 1), START TRANSACTION, UNLOCK TABLES.

Voir aussi ce paragraphe:

Les transactions ne peuvent pas être imbriquées.
[.____] Ceci est une conséquence de l'implicite commit effectuée pour toute transaction en cours lorsque vous publiez un START TRANSACTION déclaration ou un de ses synonymes.

50
Pascal MARTIN

Contrairement à la réponse de tous les autres, vous pouvez efficacement créer des transactions dans les transactions et c'est vraiment facile. Vous venez de créer des emplacements de sauvegarde et d'utiliser Rollback to SauvegardePoint Pour annuler une partie de la transaction, où SauvegardePoint Ce nom vous donnez le point de sauvegarde. Lien vers la documentation MySQL: http://dev.mysql.com/doc/refman/5.0/fr/savepoint.html Et bien sûr, aucune des requêtes nulle part dans la transaction ne doit être du type cela commettre implicitement, ou toute la transaction sera commise.

Exemples:

START TRANSACTION;

# queries that don't implicitly commit

SAVEPOINT savepoint1;

# queries that don't implicitly commit

# now you can either ROLLBACK TO savepoint1, or just ROLLBACK to reverse the entire transaction.

SAVEPOINT savepoint2;

# queries that don't implicitly commit

# now you can ROLLBACK TO savepoint1 OR savepoint2, or ROLLBACK all the way.
# e.g.

ROLLBACK TO savepoint1;
COMMIT; # results in committing only the part of the transaction up to savepoint1

In PHP J'ai écrit du code comme celui-ci, et cela fonctionne parfaitement:

foreach($some_data as $key => $sub_array) {
  $result = mysql_query('START TRANSACTION'); // note mysql_query is deprecated in favor of PDO
  $rollback_all = false; // set to true to undo whole transaction
  for($i=0;$i<sizeof($sub_array);$i++) {
    if($sub_array['set_save'] === true) {
      $savepoint = 'savepoint' . $i;
      $result = mysql_query("SAVEPOINT $savepoint");
    }
    $sql = 'UPDATE `my_table` SET `x` = `y` WHERE `z` < `n`'; // some query/queries
    $result = mysql_query($sql); // run the update query/queries

    $more_sql = 'SELECT `x` FROM `my_table`'; // get data for checking
    $result = mysql_query($more_sql);

    $rollback_to_save = false; // set to true to undo to last savepoint
    while($row = mysql_fetch_array($result)) {
      // run some checks on the data
      // if some check says to go back to savepoint:
      $rollback_to_save = true; // or just do the rollback here.
      // if some check says to rollback entire transaction:
      $rollback_all = true;
    }
    if($rollback_all === true) {
      mysql_query('ROLLBACK'); // rollback entire transaction
      break; // break out of for loop, into next foreach
    }
    if($rollback_to_save = true) {
      mysql_query("ROLLBACK TO $savepoint"); // undo just this part of for loop
    }
  } // end of for loop
  mysql_query('COMMIT'); // if you don't do this, the whole transaction will rollback
}
57
Buttle Butkus

Je veux être sûr - sont des transactions dans les transactions valables dans MySQL?

Non.

13
Vladislav Rastrusny

MySQL ne prend pas en charge les transactions imbriquées. Il y a quelques façons que vous puissiez l'imiter. Premièrement, vous pouvez utiliser des points de sauvegarde comme une forme de transaction, de sorte que vous donnez deux niveaux de transactions; J'ai utilisé cela pour tester, mais je ne suis pas sûr des limitations, si vous l'utilisez dans le code de production. Une solution plus simple est d'ignorer le deuxième begin transaction Et au lieu d'augmenter un compteur. Pour chaque commit, vous le diminuez. Une fois que vous avez frappé zéro, vous faites un commit. Il y a des limites évidentes de cela; Par exemple. Un rollback va rouler tous Transactions de retour, mais pour un cas où vous utilisez uniquement des transactions pour la manipulation des erreurs, cela peut être acceptable.

8
troelskn

Vous voudrez peut-être vérifier votre méthadologie de test. En dehors de - Maxdb , MySQL ne supporte rien à distance comme des transactions imbriquées.

1
Alan Storm
1
K. Norbert