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
语句之后启动事务(或新事务)或使用临时表。