ROLLBACK ne fonctionne pas après INSERT INTO nouvellement créé la table de destination


11

Je travaille sur un script PHP qui importe le fichier CSV ( customers.csv) dans la table MySQL ( customers).

Avant d'insérer le contenu du fichier CSV dans la table mysql, je sauvegarde d'abord la customerstable d' origine .

J'encapsule tout le processus d'importation (y compris la sauvegarde) dans une transaction mysql (pour tenir compte des cas où CSV est corrompu quelque part au milieu et pour garantir que l'importation est atomique).

Le problème est que ROLLBACK ne semble pas fonctionner lorsque je l'appelle juste après la INSERT INTOdéclaration: lors de la vérification de la base de données via phpMyAdmin, je peux voir la table nouvellement créée ET LES RANGÉES À L'INTÉRIEUR sont toujours présentes après le retour en arrière .

Voici le journal des opérations:

[2015-01-19 14:08:11] DEBUG: "START TRANSACTION" [] []
[2015-01-19 14:08:11] DEBUG: SHOW TABLES LIKE :table_name; [] []
[2015-01-19 14:08:28] DEBUG: CREATE TABLE `customers__20150119_14_08_20` LIKE `customers` [] []
[2015-01-19 14:08:37] DEBUG: INSERT INTO `customers__20150119_14_08_20` SELECT * FROM `customers` [] []
[2015-01-19 14:08:50] DEBUG: "ROLLBACK" [] []

Je me demande donc pourquoi depsite ROLLBACKest appelé, la transaction n'est pas annulée. Je comprends que ce CREATE TABLEn'est pas de nature transactionnelle et ne peut pas être annulé. Mais je supposais que INSERT INTOparce qu'il s'agit d'insérer des lignes (pas de définir un schéma), SERA en fait transactionnel, et après ROLLBACK, je me retrouverai avec une table de destination vide. Pourquoi n'est-ce pas le cas?

Et voici la sortie SHOW CREATE TABLE customers(donc ma table est InnoDb):

CREATE TABLE `customers` (
 `Code` varchar(32) NOT NULL,
 `Name` varchar(128) DEFAULT NULL,
 `Price` varchar(128) DEFAULT NULL,
 PRIMARY KEY (`Code`),
 KEY `Price` (`Price`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

et voici la sortie pour la table de desination:

CREATE TABLE `customers__20150119_14_08_20` (
 `Code` varchar(32) NOT NULL,
 `Name` varchar(128) DEFAULT NULL,
 `Price` varchar(128) DEFAULT NULL,
 PRIMARY KEY (`Code`),
 KEY `Price` (`Price`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

Le comportement est-il le même si vous réorganisez d'abord create table, alors start transaction, insert, rollback?
ypercubeᵀᴹ

J'étais sur le point de dire ça à !!!
RolandoMySQLDBA

Désactivez-vous la validation automatique de la connexion dans votre programme?
mustaccio

Réponses:


13

La raison en est que certaines déclarations, comme CREATE TABLEprovoquent un commit implicite. Vous pouvez les lire dans la documentation: Instructions qui provoquent une validation implicite .

Donc, la séquence originale des déclarations:

START TRANSACTION
SHOW TABLES LIKE customers
CREATE TABLE `customers__20150119_14_08_20` LIKE `customers`
INSERT INTO `customers__20150119_14_08_20` SELECT * FROM `customers`
ROLLBACK

s'étendra à:

START TRANSACTION ;   -- transaction context created
SHOW TABLES LIKE customers ;

COMMIT ;              -- CREATE TABLE forces commit before itself
                      --     (at this point the previous transaction is done.)
START TRANSACTION ;   -- and a new transaction  
CREATE TABLE `customers__20150119_14_08_20` 
    LIKE `customers` ;
COMMIT ;              -- CREATE TABLE forces commit after itself. 
                      -- At this point there's no transaction context

START TRANSACTION ;   --  starts a new transaction
INSERT INTO `customers__20150119_14_08_20` 
    SELECT * FROM `customers` ;
COMMIT ;              -- caused by "autocommit on" setting (guess). 

ROLLBACK ;            -- this rollback HAS NOTHING to undo

La solution serait de démarrer la transaction (ou une nouvelle) après l' CREATE TABLEinstruction ou d'utiliser une table temporaire.


@Dimitry, thnx pour l'édition.
ypercubeᵀᴹ

1
Et @RolandoMySQLDBA pour vos aimables paroles. Je suis le FGITW aujourd'hui (et seulement 15 secondes plus vite que vous;)
ypercubeᵀᴹ

@ypercube bienvenue! Il m'a fallu un certain temps pour comprendre où exactement cette TABLE DE CRÉATION sera cause an implicit commit... Il fallait donc faire ce plan sur le papier de toute façon :) @RolandoMySQLDBA merci également pour la saisie rapide. J'ai lu quelques dizaines de vos réponses l'année dernière et elles m'ont beaucoup aidé !!
Dimitry K

Vous dites donc que la validation implicite avant le INSERT, provoquée par l'instruction DDL, provoque également une validation après l'insertion?
mustaccio

1
Oui, il y a deux parties sur le raisonnement mais la partie principale à mon avis, que le PO n'a pas pu comprendre était la validation implicite par la table de création.
ypercubeᵀᴹ

3

Il semble que l'ordre des instructions soit à l'origine du problème.

Dans mon ancien verrouillage de ligne de poste dans innodb de transaction ACID , j'ai nommé 12 instructions qui interrompent une transaction par intermittence. Dans votre cas particulier, c'était la CREATE TABLEdéclaration.

Une fois que vous avez couru à l' CREATE TABLEintérieur d'un bloc START TRANSACTION... COMMIT/ROLLBACK, il n'y avait pas de cadre à restaurer.

Lancez juste CREATE TABLEavant START TRANSACTIONet ça devrait aller.

Essaie !!!

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.