INSERT INTOで新しく作成された宛先テーブルの後にROLLBACKが機能しない


11

私は、CSVファイル(customers.csv)をMySQLテーブル(customers)にインポートするPHPスクリプトに取り組んでいます。

mysqlテーブルにCSVファイルの内容を挿入する前に、最初に元のcustomersテーブルをバックアップしています。

mysqlトランザクションでインポートプロセス全体(バックアップを含む)をラップしています(CSVが途中で破損している場合を考慮し、インポートがアトミックであることを確認するため)。

問題は、ステートメントの直後にROLLBACKを呼び出したときにROLLBACKが機能しないように見えることですINSERT INTO。phpMyAdminを介してデータベースをチェックすると、新しく作成されたテーブルとROROW INSIDE ITがroollback後も存在していることがわかります。

操作のログは次のとおりです。

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

なぜdepsite ROLLBACKが呼び出されるのか、トランザクションはキャンセルされないのでしょうか。これは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年

回答:


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ᵀᴹ15年

@ypercubeへようこそ!このCREAT TABLEが正確にどこにあるのかを理解するのにしばらく時間がかかりましたcause an implicit commit...とにかくこの概要を紙に書かなければなりませんでした:) @RolandoMySQLDBAは、迅速な入力にも感謝します。昨年は数十件の返信を読みましたが、とても役に立ちました!
Dimitry K

あなたは暗黙的なコミットすることを言っているように、前にINSERT、DDL文によって引き起こされ、また何らかの形でコミットが発生した後、挿入?
Mustaccio

1
はい、推論には2つの部分がありますが、私の見解では、OPが理解できなかった主な部分は、作成テーブルによる暗黙的なコミットでした。
ypercubeᵀᴹ

3

ステートメントの順序が問題を引き起こしているようです。

ACIDトランザクションinnodb内の古いポスト行ロックで、トランザクションを断続的に中断する 12個のステートメントに名前を付けました。あなたの特定のケースでは、それはCREATE TABLE声明でした。

あなたが走った後はCREATE TABLE内部でSTART TRANSACTION... COMMIT/ROLLBACKブロック、ロールバックへの枠組みはありませんでした。

CREATE TABLEbefore START TRANSACTIONを実行するだけで大丈夫です。

試してみる !!!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.