別再用
Schema::defaultStringLength(191);
解決Specified key was too long; max key length is 767 bytes
問題了!士
的精神,要了解問題的底層,才能解決問題的本質。
> 問題描述
Laravel 在 5.4 版本之後把預設資料庫字符集更改成 utf8mb4,作為對儲存 emojis 的支援。對於那些執行 MariaDB 或舊版本的 MySQL 時,會在執行遷移時遇到下面的錯誤:
[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))
[PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes
如果你嘗試在網上找解決問題的方法,通常找到的解決方法會要你在 AppServiceProvider.php
檔案加入這一行,然後問題就沒了:
use Illuminate\Support\Facades\Schema;
public function boot()
{
Schema::defaultStringLength(191);
}
但這樣的方法只是解決了表徵,而不是本質問題。而真實原因是 Laravel 在 5.4 版本之後把預設資料庫字符集更改成 utf8mb4,作為對儲存 emojis 的支援。那為什麼 Laravel 改用 utf8mb4 編碼就會超過長度呢?
那是因為 string
資料欄位,等同於 MySQL 長度為 255 的 VARCHAR
欄位型別,所以使用 utf8
時,會使用 255 * 3 = 765
(bytes)。
當編碼改成 utf8mb4
後,每個字元固定長度為4-byte,所以大小就會有 255 * 4 = 1020
(bytes) ,而超過MySQL 用來當作索引的鍵值長度的最大值。這也就是為什麼在資料庫遷移時會報錯的原因所在。
上述解決問題的方法將 VARCHAR 的長度改成鍵值長度最大值以內。由算式767 / 4 = 191 ... 3
得知在這個範圍內若以4-byte 來儲存1 個字元,一共可以儲存191 個字元,最大長度就只會到764 bytes,符合MySQL 標準,因而解決這個問題。
但若是你資料庫已經有資料,且你無法確保現有資料中 string
資料型別的值都在 191 以下的話,就麻煩了。因此最好的解決方法不是改字元長度,而是改 MySQL 設定值。
> 解決方法
在 MySQL 5.5.14 之後,新增了一個名為 innodb_large_prefix
的功能,啟用後可將鍵值長度擴充到 3072 bytes。而這個功能相依於MySQL 5.5 新增的一個叫做Barracuda 的innodb 的檔案格式(File Formate),這個檔案格式除了支援innodb 原有的資料列格式(Row Formats),還包括了新的資料列格式:COMPRESSED和DYNAMIC。
所以要解決這個問題,就是修改 MySQL 的選項,將檔案格式改成 Barracuda,並且啟用 innodb_large_prefix 這個選項去擴充鍵值長度。最後在 遷移表格時,指定使用 DYNAMIC 的資料列格式即可。
在 MySQL 的設定檔 my.conf
(或 my.ini
) 修改為:(記得先備份資料庫)
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
innodb_large_prefix=1
innodb_file_per_table=1
innodb_file_format=Barracuda
innodb_default_row_format=DYNAMIC
[mysqldump]
default-character-set = utf8mb4
接著在 Laravel 的 config/database.php
的 mysql
索引修改 engine
這一行,讓 Laravel 在執行資料時,預設都是使用 Dynamic 的存取方法執行程式。
'mysql' => [
...
'engine' => 'InnoDB ROW_FORMAT=DYNAMIC',
...
],
以上,歡迎指教
參考資料
本作品採用《CC 協議》,轉載必須註明作者和本文連結