はじめに
古い備忘録だが、いまだに定期的にアクセスがあるので全面的に加筆修正した。
PHPやLaravelは新しいバージョンに追従していても、MySQLのバージョンはいまだ5.5~5.6、という環境も多いのだろう。
※2023年追記:すでにLaravel5系、MySQL5.6系ともにサポートの切れたかなり古いバージョンとなっているので、なるべくバージョンアップにて解決することを推奨する。
前提
- Laravel5.4以上
- MySQL5.7.7未満
現象
上記環境のもとで、$ php artisan make:auth
で自動作成されるマイグレーションファイルに対し、
$ php artisan migrate
を実行すると、以下のエラーが発生する。
[Illuminate\Database\QueryException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was t
oo long; max key length is 767 bytes (SQL: alter tableusers
add uniqueusers_email_unique
(
[PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was t
oo long; max key length is 767 bytes
原因
1. Laravel5.4から標準charasetがutf8mb4に変わった
標準charasetがutf8mb4となったことで1文字あたりの最大byte数が4bytesに増えた。
2. MySQL5.7.7未満ではユニーク制約を付けたカラムは最大767bytes
マイグレーションファイルにvarcharカラムの大きさを指定しなかった場合、varchar(255)
のカラムが作成される。
$table->string('email')->unique();
一方、MySQL5.7.7以前のバージョンでは、PRIMARY_KEYおよびUNIQUE_KEYを付けたカラムには最大767bytesまでしか入らない。
4bytes,255文字では767bytesを超えてしまう。これがエラーの原因。
対策
対策としては以下の3つが考えられる。
- MySQLのバージョンを最新にする
- 使用するcharasetをutf8mb4から変更する
- カラムの最大長を変更し、767bytes以上の文字列が入らないようにする
対策1:MySQLのバージョンを最新にする
特段の事情がなければベストの対応。MySQL5.6系のPremier Support期限は2018年2月に終了している。
対策2:使用するcharasetをutf8mb4から変更する
Laravel5.3まではcharsetの標準設定はUTF-8だった。
config/database.php
よりcharsetを以下のように変更すれば、Laravel5.3以前と同じ挙動で使用することができる。
ただし、絵文字 など、4バイトで表現される文字は使えなくなる。
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
対策3:カラムの最大長を変更し、767bytes以上の文字列が入らないようにする
varchar(191)
のカラムを作成すれば、191 * 4 = 764bytesのため、エラーが発生しない。
//個別で指定する例
$table->string('email', 191)->unique();
上記のようにカラムごと個別に最大長を指定してもよいが、
app\Providers\AppServiceProvider.php
に以下の記載を追加することで、最大長未指定時のdefault値を変更することが可能である。
use Illuminate\Support\Facades\Schema;
public function boot()
{
Schema::defaultStringLength(191);
}
これでマイグレーションを実行すれば、正常に動作する。