Ошибка миграции БД в Laravel: Specified key was too long

Опубликовано: Комментариев: 0
Ошибка миграции БД в Laravel: Specified key was too long

Согласно информации портала laravel-news, начиная с версии Laravel 5.4 были внесены изменения в дефолтный charset базы данных. Если быть более точным, то 25.10.2016 года Taylor Otwell сделал соответствующий коммит с аннотацией "use utf8mb4 as default character set". Данная кодировка поддерживает хранение emoji.

Таким образом, во всех современных релизах Laravel, после 25.10.16 установлена кодировка по умолчанию utf8mb4. Именно она и вызывает ошибку Specified key was too long. Однако, ошибка не должна проявляться при выполнении миграции для БД MySQL v5.7.7 или старше или MariaDB старше чем 10.2.2.

Но что же делать, если у Вас все таки при выполнении миграций:

php artisan migrate

 в консоли появляется вот такая неприятная ошибка?

Illuminate\Database\QueryException  : SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 1000 bytes (SQL: alter table `users` add unique `users_email_unique`(`email`))

Exception trace:

1   Doctrine\DBAL\Driver\PDOException::("SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 1000 bytes")

Ну что же, если Вам не повезло и подобная ошибка все таки появилась - не расстраивайтесь. Она довольно быстро и легко исправляется и сейчас я расскажу, как это можно сделать.

Варианты исправления ошибки Laravel: Specified key was too long

Собственно, как и всегда, у нас на выбор есть несколько вариантов решения данной проблемы. Рассмотрим их далее по очереди:

1. Переход на более новую версию MySQL

Это наиболее очевидный вариант. И если вы только создаете новое приложение, то конечно же лучше сразу выбрать более новую версию MySQL. Зачем разрабатывать на устаревших технологиях? Но! Если у вас шаред хостинг, то скорее всего опция смены версии БД у вас отсутствует.

2.  Изменить параметр defaultStringLegth

Если открыть оф. документацию Laravel в разделе "Создание Индексов", то разработчики фреймворка советуют установить вручную параметр defaultStringLegth равным 191 символам для более старых версий MySQL или MariaDB. Сделать это возможно, вызвав метод Schema::defaultStringLength внутри AppServiceProvider. Для этого открываем файл:

nano app/Providers/AppServiceProvider.php

и добавляем вызов в методе boot, предварительно импортировав неймспейс Schema:

use Illuminate\Support\Facades\Schema;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Schema::defaultStringLength(191);
}

После этого Ваши миграции будут успешно выполняться.

3. Уменьшить длину строки в отдельно взятой миграции

Вместо глобального изменения длины строки для всех миграций, возможно изменить длину строки непосредственно для определенной таблицы. К примеру, изменим значение длины строки для миграции, создающей таблицу пользователей:

Schema::defaultStringLength(191);

Schema::create('users', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});

4. Уменьшить длину индекса, но не уменьшать длину строки

Аналогично, тому как можно устанавливать длину строки непосредственно при выполнении миграции в отедльно взятую таблицу, можно уменьшить длину индекса в поле, но не уменьшать при этом длину самого поля. Для этого все в том же файле миграции нужно добавить:

$table->index([DB::raw('email(191)')]);

5. Изменить кодировку в таблице на utf8

Не знаю как Вам, но лично мне не сильно нравится рекомендуемый вариант с уменьшением длины строки. Вместо этого я предпочитаю изменить кодировку по умолчанию в своей БД на utf8, т.к. хранить emoji я в ней явно не планирую. За одно я всегда помимо смены кодировки (charset), еще и меняю сравнение (collation) на utf8_general_ci. Для этого в файле конфигурации БД:

nano app/config/database.php

я меняю для mySQL соответствующие значения на:

'charset' => 'utf8',
'collation' => 'utf8_general_ci',

Теперь у Вас всё должно работать как полагается! Если у Вас остались вопросы - смело задавайте в комментариях.