ROLLBACK не работает после INSERT INTO вновь созданной таблицы назначения

11

Я работаю над PHP-скриптом, который импортирует файл CSV ( customers.csv) в таблицу MySQL ( customers).

Перед тем, как вставить содержимое CSV-файла в таблицу mysql, я сначала создаю резервную копию исходной customersтаблицы.

Я обертываю весь процесс импорта (включая резервное копирование) в транзакцию mysql (чтобы учесть случаи, когда CSV поврежден где-то посередине, и гарантировать, что импорт атомарен).

Проблема в том, что ROLLBACK, похоже, не работает, когда я вызываю его сразу после INSERT INTOоператора: при проверке базы данных через phpMyAdmin я вижу новую созданную таблицу, и строки внутри нее все еще присутствуют после отката .

Вот журнал операций:

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

Поэтому интересно, почему ROLLBACKназывается depsite , транзакция не отменена. Я понимаю, что CREATE TABLEэто не транзакционный характер и его нельзя откатить. Но я предполагал, что INSERT INTOпоскольку он имеет дело со вставкой строк (не определяя схему), на самом деле он будет транзакционным, а после ROLLBACK у меня останется пустая таблица назначения. Почему это не так?

И вот вывод SHOW CREATE TABLE customers(так что моя таблица 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

и вот вывод для таблицы назначения:

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
Димитрий К
источник
Является ли поведение так же , если вы реорганизовать в первый create table, а затем start transaction, insert, rollback?
ypercubeᵀᴹ
Я как раз собирался сказать это !!!
RolandoMySQLDBA
Вы отключаете автокоммит на соединение в вашей программе?
Мустаччо

Ответы:

13

Причина в том, что некоторые утверждения, например, CREATE TABLEвызывают неявную фиксацию. Вы можете прочитать о них в документации: Заявления, которые вызывают неявную фиксацию .

Итак, оригинальная последовательность утверждений:

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

будет расширяться в:

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

Решением будет запуск транзакции (или новой) после CREATE TABLEоператора или использование временной таблицы.

ypercubeᵀᴹ
источник
@Dimitry, спасибо за редактирование.
ypercubeᵀᴹ 19.01.15
1
И @RolandoMySQLDBA за ваши добрые слова. Я FGITW сегодня (и всего на 15 секунд быстрее, чем вы;)
ypercubeᵀᴹ
@ypercube добро пожаловать! Мне потребовалось некоторое время, чтобы понять, где именно будет этот CREAT TABLE cause an implicit commit... Так или иначе, мы должны были сделать этот набросок на бумаге :) Спасибо @RolandoMySQLDBA за быстрый ввод. Я прочитал несколько десятков ваших ответов за последний год, и они мне очень помогли !!
Димитрий К
Так вы говорите , что неявное обязательство передINSERT тем , вызванное утверждением DDL, а также каким - то образом приводит к фиксации после вставки?
Мустаччо
1
Да, рассуждение состоит из двух частей, но, на мой взгляд, основная часть, которую ОП не смог выяснить, была неявная фиксация таблицей создания.
ypercubeᵀᴹ
3

Похоже, что порядок утверждений вызывает проблему.

В моей старой блокировке пост-записи в транзакции ACID innodb я назвал 12 операторов, которые прерывали транзакцию с перерывами. В вашем конкретном случае это было CREATE TABLEутверждение.

После того, как вы запустили CREATE TABLEвнутри START TRANSACTION... COMMIT/ROLLBACKблока, откатов уже не было.

Просто запустите CREATE TABLEдо START TRANSACTIONи все будет в порядке.

Попробуйте!

RolandoMySQLDBA
источник