web-dev-qa-db-fra.com

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

Je travaille sur un script PHP qui importe un 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 table customers 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 INSERT INTO instruction: 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 encore présentes après roollback.

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 ROLLBACK est appelé, la transaction n'est pas annulée. Je comprends que CREATE TABLE n'est pas de nature transactionnelle et ne peut pas être annulé. Mais je supposais que INSERT INTO car il traite de l'insertion de lignes (pas de définition de 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
11
Dimitry K

La raison en est que certaines déclarations, comme CREATE TABLE provoque une validation implicite. Vous pouvez les lire dans la documentation: Déclarations qui provoquent un engagement 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 le CREATE TABLE ou utilisez une table temporaire.

13
ypercubeᵀᴹ

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

Dans mon ancien article verrouillage des lignes dans la transaction ACID innodb , j'ai nommé 12 instructions qui interrompent une transaction par intermittence. Dans votre cas particulier, c'était le CREATE TABLE déclaration.

Une fois que vous avez exécuté CREATE TABLE à l'intérieur d'un START TRANSACTION ... COMMIT/ROLLBACK block, il n'y avait pas de framework à restaurer.

Exécutez simplement le CREATE TABLE avant START TRANSACTION et ça devrait aller.

Essaie !!!

3
RolandoMySQLDBA