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
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.
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 !!!