ROLLBACK tidak berfungsi setelah Sisipkan ke dalam tabel tujuan yang baru dibuat

11

Saya sedang mengerjakan skrip PHP yang mengimpor file CSV ( customers.csv) ke dalam tabel MySQL ( customers).

Sebelum memasukkan isi file CSV ke tabel mysql, saya pertama-tama membuat cadangan customerstabel asli .

Saya membungkus seluruh proses impor (termasuk mencadangkan) dalam transaksi mysql (untuk menjelaskan kasus-kasus ketika CSV rusak di suatu tempat di tengah, dan untuk memastikan impor bersifat atomik).

Masalahnya adalah bahwa ROLLBACK tampaknya tidak berfungsi ketika saya memanggilnya setelah INSERT INTOpernyataan: ketika memeriksa database melalui phpMyAdmin saya bisa melihat tabel yang baru dibuat DAN BARIS DI DALAMNYA masih ada setelah roollback .

Berikut log operasi:

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

Jadi saya bertanya-tanya mengapa depsite ROLLBACKdisebut, transaksi tidak dibatalkan. Saya mengerti itu CREATE TABLEbukan transaksional dan tidak dapat dibatalkan. Tapi saya berasumsi bahwa INSERT INTOkarena berurusan dengan memasukkan baris (tidak mendefinisikan skema), AKAN sebenarnya akan transaksional, dan setelah ROLLBACK saya akan dibiarkan dengan tabel tujuan kosong. Mengapa tidak demikian?

Dan inilah output SHOW CREATE TABLE customers(jadi meja saya 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

dan inilah output untuk tabel 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
Dimitry K
sumber
Apakah perilaku yang sama jika Anda menyusun ulang untuk pertama create table, kemudian start transaction, insert, rollback?
ypercubeᵀᴹ
Aku baru saja akan mengatakan itu pada !!!
RolandoMySQLDBA
Apakah Anda menonaktifkan autocommit pada koneksi di program Anda?
mustaccio

Jawaban:

13

Alasannya adalah bahwa beberapa pernyataan, seperti CREATE TABLEmenyebabkan komit implisit. Anda dapat membacanya di dokumentasi: Pernyataan yang Menyebabkan Komitmen Tersirat .

Jadi urutan asli dari pernyataan:

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

akan berkembang menjadi:

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

Solusinya adalah memulai transaksi (atau yang baru) setelah CREATE TABLEpernyataan atau menggunakan tabel sementara.

ypercubeᵀᴹ
sumber
@ Demitry, thnx untuk edit.
ypercubeᵀᴹ
1
Dan @RolandoMySQLDBA untuk kata-kata baik Anda. Saya FGITW hari ini (dan hanya 15 detik lebih cepat dari Anda;)
ypercubeᵀᴹ
@ selamat datang, selamat datang! Butuh beberapa saat untuk mencari tahu di mana tepatnya CREAT TABLE ini akan cause an implicit commit... Jadi harus melakukan garis besar ini di atas kertas :) @RolandoMySQLDBA terima kasih atas masukan yang cepat juga. Saya telah membaca beberapa lusin balasan Anda pada tahun lalu dan mereka banyak membantu saya !!
Dimitry K
Jadi kau mengatakan bahwa implisit komit sebelum itu INSERT, disebabkan oleh pernyataan DDL, juga entah bagaimana menyebabkan komit setelah insert?
mustaccio
1
Ya, ada dua bagian pada alasan tetapi bagian utama dalam pendapat saya, bahwa OP tidak bisa mencari tahu adalah komitmen implisit oleh tabel buat.
ypercubeᵀᴹ
3

Sepertinya urutan pernyataan yang menyebabkan masalah.

Dalam penguncian baris posting lama saya di innodb transaksi ACID , saya menyebutkan 12 pernyataan yang memecah transaksi sesekali. Dalam kasus khusus Anda, itu adalah CREATE TABLEpernyataan.

Setelah Anda berlari CREATE TABLEdi dalam START TRANSACTION... COMMIT/ROLLBACKblok, tidak ada kerangka untuk mengembalikan.

Jalankan saja CREATE TABLEsebelumnya START TRANSACTIONdan Anda harus baik-baik saja.

Cobalah !!!

RolandoMySQLDBA
sumber