muraveです。LTSを使いたい人なのでLaravelのバージョンが5.1から5.5にジャンプアップしました。
その際、いままで使っていたデータベースバックアップのプラグインが使えなくなりました。
データベースdumpをお手軽にとったりもどしたりしたかっただけだったんだけど、重厚なバックアップ用パッケージが見つかった。これはこれで入れとくかぁ。
— murave (@murave) 2017年11月24日
ということで
https://github.com/spatie/laravel-backup
を導入。良い感じです。もしかして?と、この方のリポジトリを探してみたらありました。
https://github.com/spatie/laravel-db-snapshots
This package provides Artisan commands to quickly dump and load databases in a Laravel application.
そうそう、この記事の対象データベースはPostgreSQLです。
PostgreSQLの場合にレストア時にエラーでデータベースを飛ばしたので、その対処方法のメモだったりします。MySQL、SQLiteにも対応らしいですが試してません。導入や使い方はドキュメント見てくださいね。
ドキュメント通りにスナップショットをロード(restore)しようとしたらエラーでコケたのでした。
# artisan snapshot:load my-first-dump
[Illuminate\Database\QueryException]
SQLSTATE[42601]: Syntax error: 7 ERROR: syntax error at or near "\"
LINE 464: \.
^ (SQL: --
### 以下略
で、コケるとデータベース飛びます(掃除がリストアの前に別途行われるようです)。
バックアップ・リストアのテストしててバックアップオプションを変えてからデータのバックアップが取れないと思ってたら、リストアのテストの失敗でデータが消滅してたせいだった。
— murave (@murave) 2017年11月27日
こんあとき、ボクのように上書きで再度スナップショットを取ると空のデータベースのdumpで上書きという悲劇が起こるので気をつけましょう。
dumpファイルの内容を調べるとCOPY from stdinで.から読むようになってるところでコケてます。
「ははーん。pg_dump呼び出しに–insertsつければいいんだな」
pg_dumpに–insertsオプションをつけるとデータをCOPYではなくINSERTコマンドでdumpします。
「どうやってつけたらいいんだ?」
コードを追ったらdatabase.phpでdumpのオプション付けられるようになってました。
insertsオプションにも対応してます。サンプル載せときます。
'pgsql' => [
'driver' => 'pgsql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '5432'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
'schema' => 'public',
'sslmode' => 'prefer',
//PDO絡みで環境によって型がばらつく可能性があるので割り切って全て文字列で取得。
'options' => [
PDO::ATTR_STRINGIFY_FETCHES => true,
],
'dump' => [
'useInserts',
],
],
‘dump’ => [‘useInserts’] の所です。無事snapshot:loadできるようになりました。
# artisan snapshot:create for-test-dump
# artisan --env=testing snapshot:load for-test-dump
これはデフォルトの環境でスナップショットを取ってtesting環境でロード(restore)してます。
前記database.phpのサンプルのコメントにありますが、開発環境ではintで取れてたのに本番のサーバーにデプロイしたらstringで返ってくるなどデータ取得時に動作環境によって型がばらつくことがあります。
厳密比較の動作が異なって判定が変わったり、unit testがコケたりと困ったことになるので全て文字列で取得するオプションを設定するようにしています。
Model経由で値を扱う場合は
/**
* キャスト設定(文字列以外は要設定)
*
* @var array
*/
protected $casts = [
'id' => 'integer',
'updated_by' => 'integer',
'options' => 'array', //jsonb
];
のように$castsに書いておけばLaravelさんがキャストしてくれます。
タグ: Laravel, PostgreSQL