INSERT INTO 新创建的目标表后 ROLLBACK 不起作用

Dim*_*y K 12 mysql innodb transaction rollback

我正在研究将 CSV 文件 ( customers.csv) 导入 MySQL 表 ( customers) 的PHP 脚本。

在将 CSV 文件的内容插入 mysql 表之前,我首先备份原始customers表。

我将整个导入过程(包括备份)包装在一个 mysql 事务中(以解决 CSV 在中间某处损坏的情况,并确保导入是原子的)。

问题是当我在INSERT INTO语句之后立即调用它时 ROLLBACK 似乎不起作用:通过 phpMyAdmin 检查数据库时,我可以看到新创建的表和 ROWS INSIDE IT 在 rollback 后仍然存在

以下是操作日志:

[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" [] []
Run Code Online (Sandbox Code Playgroud)

所以我想知道为什么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
Run Code Online (Sandbox Code Playgroud)

这是目的地表的输出:

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
Run Code Online (Sandbox Code Playgroud)

ype*_*eᵀᴹ 15

原因是某些语句,例如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
Run Code Online (Sandbox Code Playgroud)

将扩展为:

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
Run Code Online (Sandbox Code Playgroud)

解决方案是在CREATE TABLE语句之后启动事务(或新事务)或使用临时表。