ROLLBACK non funziona dopo INSERT INTO nella tabella di destinazione appena creata


11

Sto lavorando allo script PHP che importa il file CSV ( customers.csv) nella tabella MySQL ( customers).

Prima di inserire il contenuto del file CSV nella tabella mysql, eseguo il backup della customerstabella originale .

Sto avvolgendo l'intero processo di importazione (incluso il backup) in una transazione mysql (per tenere conto dei casi in cui CSV è danneggiato da qualche parte nel mezzo e per garantire che l'importazione sia atomica).

Il problema è che ROLLBACK non sembra funzionare quando lo chiamo subito dopo la INSERT INTOdichiarazione: quando controllo il database tramite phpMyAdmin posso vedere la tabella appena creata E LE FILE ALL'INTERNO sono ancora presenti dopo il roollback .

Ecco il registro delle operazioni:

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

Quindi mi chiedo perché ROLLBACKviene chiamato depsite , la transazione non viene annullata. Capisco che CREATE TABLEnon è di natura transazionale e non può essere ripristinato. Ma supponevo che, INSERT INTOpoiché si tratta di inserire righe (non definendo lo schema), SARANNO effettivamente transazionali e dopo ROLLBACK rimarrò con una tabella di destinazione vuota. Perché non è così?

Ed ecco l'output SHOW CREATE TABLE customers(quindi la mia tabella è 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

ed ecco l'output per la tabella di 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

Il comportamento è lo stesso se riordini per primo create table, allora start transaction, insert, rollback?
ypercubeᵀᴹ

Stavo per dirlo a !!!
RolandoMySQLDBA

Disabiliti autocommit sulla connessione nel tuo programma?
Mustaccio

Risposte:


13

Il motivo è che alcune dichiarazioni, come CREATE TABLEcausano un impegno implicito. Puoi leggerli nella documentazione: Dichiarazioni che causano un impegno implicito .

Quindi la sequenza originale di affermazioni:

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

si espanderà 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

La soluzione sarebbe quella di avviare la transazione (o una nuova) dopo l' CREATE TABLEistruzione o utilizzare una tabella temporanea.


@Dimitry, thnx per la modifica.
ypercubeᵀᴹ

1
E @RolandoMySQLDBA per le tue parole gentili. Sono il FGITW oggi (e solo 15 secondi più veloce di te;)
ypercubeᵀᴹ

@ypercube benvenuto! Mi ci è voluto un po 'di tempo per capire esattamente dove sarà questa CREAT TABLE cause an implicit commit... Quindi ho dovuto fare comunque questo schema su carta :) @RolandoMySQLDBA grazie anche per un rapido input. Ho letto alcune dozzine delle tue risposte nell'ultimo anno e mi hanno aiutato molto !!
Dimitry K,

Quindi stai dicendo che l'implicito commit prima che la INSERT, causata dalla dichiarazione DDL, anche in qualche modo provoca un commit dopo l'inserto?
Mustaccio

1
Sì, ci sono due parti nel ragionamento, ma la parte principale secondo me, che l'OP non è riuscito a capire, era l'impegno implicito della tabella di creazione.
ypercubeᵀᴹ

3

Sembra che l'ordine delle istruzioni stia causando il problema.

Nel mio vecchio blocco delle righe postali all'interno della transazione ACID innodb , ho nominato 12 istruzioni che interrompono una transazione in modo intermittente. Nel tuo caso particolare, è stata la CREATE TABLEdichiarazione.

Una volta eseguito CREATE TABLEall'interno di un START TRANSACTION... COMMIT/ROLLBACKblocco, non c'era alcun framework per il rollback.

Esegui il CREATE TABLEprima START TRANSACTIONe dovresti stare bene.

Provaci !!!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.