11940


Laravel5.0で行数の多いCSVファイルの内容を MySQL の「LOAD DATA local INFILE
〜」コマンドを使ってデータベースを書き換えようとしています。  
既存の内容を新しい内容で完全に置き換えるので、一旦内容を truncate
してから書き込むようにしていますが、タイムアウトなどで処理が中断されてしまった場合はロールバックさせるために次のようにしました。（$destination
にはファイルの場所が格納されています。）

[code]

    $query = sprintf("LOAD DATA local INFILE '%s' INTO TABLE `zip_codes` FIELDS TERMINATED BY ','
     OPTIONALLY ENCLOSED BY '\"' ESCAPED BY '\"' LINES TERMINATED BY '\n'
      IGNORE 0 LINES (`zip`, `address1`, `address2`, `address3`)", addslashes($destination));
    
    $pdo = DB::connection()->getpdo();
    $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
    try {
        $pdo->beginTransaction();
        $pdo->exec("TRUNCATE TABLE `zip_codes`");
        $pdo->exec($query);
        $pdo->commit();
    }catch(\PDOException $e){
        $pdo->rollBack();
    }
    
[/code]

わざと存在しないファイル名を指定すると catch 部分は実行されているようですが内容は truncate で消去された状態のままでした。

専用の DB::transaction() や、DB::beginTransaction()、DB::rollback() を使ってみても catch
処理が行われる前にフレームワーク側で catch されてしまっているようで同じような結果になりました。

このような場合どのようにしてロールバック処理を行えばいいのでしょうか。  
よろしくお願いします。


CC BY-SA 3.0
2015-07-02T02:40:30.403
11937
2015-07-02T04:41:17.757
2015-07-02T04:41:17.757
10083
10083
question
php mysql
MySQLでPDOのエラー時にロールバックされない


ファイルが存在しない時は、PDOException以外のExceptionが上がってきているかも知れません。まずは、Exceptionクラスをハンドリングしてチェックしてみては？

[code]

    try {
        $pdo->beginTransaction();
        $pdo->exec("TRUNCATE TABLE `zip_codes`");
        $pdo->exec($query);
    } catch (\PDOException $e) {
        dd(get_class($e));
    
        $pdo->rollBack();
    } catch (\Exception $e) {
        dd(get_class($e));
    }
    
[/code]


CC BY-SA 3.0
2015-07-02T03:17:23.920
11939
2015-07-02T03:17:23.920
9529
11937
answer


（コメントに書いていましたが、Whoopsに関する記述が削除されたようなので回答にします）

MySQL では TRUNCATE
時に自動でコミットが行われます。したがってTRUNCATE自体はもちろん、それ以前に行った操作も、TRUNCATE後にロールバックすることはできません。

  * [MySQL :: MySQL 5.7 Reference Manual :: 13.1.29 TRUNCATE TABLE Syntax](http://dev.mysql.com/doc/refman/5.7/en/truncate-table.html)
  * [TRUNCATE (SQL) - Wikipedia](https://ja.wikipedia.org/wiki/TRUNCATE_\(SQL\))

なお、PHPの [`set_exception_handler()`](http://php.net/manual/ja/function.set-
exception-handler.php) では例外 **発生時**
にハンドリングすることはできませんから、通常そのようなことはないと考えてよいと思います。

> 例外が try/catch ブロックの中でキャッチされなかった場合の デフォルトの例外ハンドラを設定します。 例外は、exception_handler
> がコールされた後に 停止します。


CC BY-SA 3.0
2015-07-02T03:52:14.730
11940
2015-07-02T03:52:14.730
8000
11937
answer


MySQLでは`TRUNCATE`はRollbackできないみたいです。  
`DELETE`を使うとRollbackできます。

参考サイト  
<http://www.sria.co.jp/blog/2014/08/mysql-can-do-rollback-truncate/>


CC BY-SA 3.0
2015-07-02T03:57:27.600
11941
2015-07-02T03:57:27.600
9529
11937
answer