ROLLBACK funktioniert nach dem Einfügen in eine neu erstellte Zieltabelle nicht

11

Ich arbeite an einem PHP-Skript, das CSV-Datei ( customers.csv) in MySQL table ( customers) importiert .

Bevor ich den Inhalt der CSV-Datei in die MySQL-Tabelle einfüge, sichere ich zuerst die ursprüngliche customersTabelle.

Ich verpacke den gesamten Importprozess (einschließlich der Sicherung) in eine MySQL-Transaktion (um Fälle zu berücksichtigen, in denen CSV irgendwo in der Mitte beschädigt ist, und um sicherzustellen, dass der Import atomar ist).

Das Problem ist, dass ROLLBACK nicht zu funktionieren scheint, wenn ich es direkt nach der INSERT INTOAnweisung aufrufe: Wenn ich die Datenbank über phpMyAdmin überprüfe, sehe ich die neu erstellte Tabelle UND REIHEN INNERHALB, die nach dem Roollback noch vorhanden sind .

Hier ist das Protokoll der Operationen:

[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" [] []

Ich frage mich also, warum depsite ROLLBACKaufgerufen wird und die Transaktion nicht abgebrochen wird. Ich verstehe, dass dies CREATE TABLEnicht transaktionaler Natur ist und nicht zurückgesetzt werden kann. Aber ich ging davon aus, dass, INSERT INTOda es sich um das Einfügen von Zeilen handelt (ohne das Schema zu definieren), tatsächlich transaktional sein wird und nach ROLLBACK eine leere Zieltabelle übrig bleibt. Warum ist das nicht der Fall?

Und hier ist die Ausgabe SHOW CREATE TABLE customers(so ist meine Tabelle 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

und hier ist die Ausgabe für die Zieltabelle:

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
Dimitry K.
quelle
Ist das gleiche Verhalten , wenn Sie zuerst neu anordnen create table, dann start transaction, insert, rollback?
Ypercubeᵀᴹ
Ich wollte das gerade sagen !!!
RolandoMySQLDBA
Deaktivieren Sie die automatische Festschreibung für die Verbindung in Ihrem Programm?
Mustaccio

Antworten:

12

Der Grund ist, dass einige Anweisungen, wie z. B. CREATE TABLEein implizites Commit verursachen. Sie können darüber in der Dokumentation lesen: Anweisungen, die ein implizites Commit verursachen .

Also die ursprüngliche Reihenfolge der Aussagen:

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

wird erweitern in:

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

Die Lösung wäre, die Transaktion (oder eine neue) nach der CREATE TABLEAnweisung zu starten oder eine temporäre Tabelle zu verwenden.

ypercubeᵀᴹ
quelle
@Dimitry, danke für die Bearbeitung.
Ypercubeᵀᴹ
1
Und @RolandoMySQLDBA für Ihre freundlichen Worte. Ich bin heute die FGITW (und nur 15 Sekunden schneller als du;)
ypercubeᵀᴹ
@ypercube willkommen! Ich habe eine Weile gebraucht, um herauszufinden, wo genau diese CREAT TABLE sein wird cause an implicit commit... Also musste ich diese Gliederung sowieso auf Papier machen :) @RolandoMySQLDBA danke auch für die schnelle Eingabe. Ich habe im letzten Jahr einige Dutzend Ihrer Antworten gelesen und sie haben mir sehr geholfen !!
Dimitry K
Sie sagen also, dass das implizite Festschreiben vor dem INSERT, verursacht durch die DDL-Anweisung, auch irgendwie ein Festschreiben nach dem Einfügen verursacht?
Mustaccio
1
Ja, es gibt zwei Teile der Argumentation, aber der Hauptteil meiner Meinung nach, den das OP nicht herausfinden konnte, war das implizite Festschreiben durch die Erstellungs-Tabelle.
Ypercubeᵀᴹ
3

Es sieht so aus, als ob die Reihenfolge der Anweisungen das Problem verursacht.

In meiner alten Post- Row-Sperre innerhalb der ACID-Transaktion innodb habe ich 12 Anweisungen benannt, die eine Transaktion zeitweise unterbrechen. In Ihrem speziellen Fall war es die CREATE TABLEAussage.

Sobald Sie CREATE TABLEin einem START TRANSACTION... COMMIT/ROLLBACKBlock gelaufen sind , gab es kein Framework zum Zurücksetzen.

Führen Sie einfach das CREATE TABLEvorher START TRANSACTIONund Sie sollten in Ordnung sein.

Versuche es !!!

RolandoMySQLDBA
quelle