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


11

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

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

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

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

这是操作日志:

[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 2015年

您是否在程序中的连接上禁用了自动提交?
mustaccio 2015年

Answers:


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


@ Dimitry,thnx进行编辑。
ypercubeᵀᴹ

1
还有@RolandoMySQLDBA代表您的好话。我今天是FGITW(仅比您快15秒;)
ypercubeᵀᴹ2015年

@ypercube欢迎您!我花了一段时间才弄清楚这个CREAT TABLE的确切位置cause an implicit commit...所以无论如何都必须在纸上做这个大纲:) @RolandoMySQLDBA也感谢您的快速输入。去年我读了几十封您的回信,它们对我有很大帮助!
Dimitry K

所以你说的是,隐性提交之前INSERT,所造成的DDL语句,也不知何故导致提交插入?
mustaccio 2015年

1
是的,推理有两个部分,但我认为主要的部分是,OP无法弄清楚创建表的隐式提交。
ypercubeᵀᴹ

3

看起来语句的顺序导致了问题。

ACID事务innodb中锁定的旧帖子行中,我命名了12条语句,这些语句会间歇性地中断事务。在您的特定情况下,这就是CREATE TABLE声明。

一旦您CREATE TABLESTART TRANSACTION... COMMIT/ROLLBACK块中运行,就没有回滚的框架。

只需运行CREATE TABLE之前START TRANSACTION,就可以了。

试试看 !!!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.