【Laravel】 Specified key was too long; max key length is 767 bytes
◾️エラー概要
Laravel5.5でmigrationを実行したところ、以下のエラー発生。
[Illuminate\Database\QueryException] SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table `users` add unique `users_email_unique`(`email`)) [Doctrine\DBAL\Driver\PDOException] SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes [PDOException] SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes
◾️原因
Laravel5.4から、標準charasetがutf8mb4に変わった。
標準charasetがutf8mb4となったことで1文字あたりの最大byte数が4bytesに増えた。
MySQLではユニーク制約を付けたカラムには767bytesまでしか入らない。
MySQLではPRIMARY_KEYおよびUNIQUE_KEYを付けたカラムには、
768bytes以上のカラムに対するインデックスキーは設定できません!
※5.7.7以降のバージョンだと解消されているみたい。
Laravelの場合、データベースのcharasetは「config/database.php」で定義されているので確認してみましょう。
Laravel5.3までは、以下のようにUTF-8。
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
UTF-8は1文字が3bytesのため、
varchar(255)は255文字 × 3bytes=765bytes。
問題なくインデックスを設定することができていました。
Laravel5.4からは、utf8mb4が標準になりました。
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
utf8mb4は1文字4bytesとしてあつかわれるため、
制限の767バイトを超えてしまい、MySQLのエラーが出力されるようになりました。
◾️解決策
【app\Providers\AppServiceProvider.php】の、boot()を下のように書き換えて上書き。
一度MySQLを落として、再度migrateしたら無事解決されました。
use Illuminate\Support\Facades\Schema;
public function boot()
{
Schema::defaultStringLength(191);
}