Миграция Laravel: уникальный ключ слишком длинный, даже если указан


166

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

[Illuminate \ Database \ QueryException] SQLSTATE [42000]: синтаксическая ошибка или нарушение доступа: 1071 Указанный ключ слишком длинный; максимальная длина ключа составляет 767 байт (SQL: изменить таблицу, usersдобавить уникальный users_email_uniq ( email))

моя миграция выглядит следующим образом:

Schema::create('users', function(Blueprint $table)
{
    $table->increments('id');
    $table->string('name', 32);
    $table->string('username', 32);
    $table->string('email', 320);
    $table->string('password', 64);
    $table->string('role', 32);
    $table->string('confirmation_code');
    $table->boolean('confirmed')->default(true);
    $table->timestamps();

    $table->unique('email', 'users_email_uniq');
});

После некоторого поиска в Google я наткнулся на этот отчет об ошибке, где Тейлор говорит, что вы можете указать ключ индекса как 2-й параметр unique(), что я и сделал. Это все еще дает ошибку. Что здесь происходит?


Почему вы используете 320 символов для электронной почты? Это может быть вашей проблемой.
Антонио Карлос Рибейро

1
Это была действительно проблема, не знаю почему. Но да, вы правы, я не знаю, почему я указал длину символа для каждого поля.
Сняли

Забавно, что никто не предложил использовать поле фиксированной длины, которое содержит хэш электронной почты и вуаля - проблема, решаемая навсегда, для любой среды и для любой реляционной базы данных. Потому что именно так мы гарантируем уникальность - используя фиксированное число входных данных переменной длины, учитывая тот факт, что числовой диапазон достаточно велик (и для sha1 / sha256 это так).
NB

1
laravel-news.com/laravel-5-4-key-too-long-error может получить помощь
matinict

Ответы:


280

Укажите меньшую длину для вашей электронной почты:

$table->string('email', 250);

Что по умолчанию, на самом деле:

$table->string('email');

И тебе должно быть хорошо.

Для Laravel 5.4 вы можете найти решение в этом Laravel 5.4: Указанный ключ был слишком длинной ошибкой, Laravel News post:

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

use Illuminate\Database\Schema\Builder;


public function boot()
{
    Builder::defaultStringLength(191);
}

6
Максимально возможная длина электронной почты, 254вероятно, стоит иметь в виду, поэтому я бы, вероятно, проверил уникальность, используя валидатор в этом случае.
Себастьян Сулински

12
Для Laravel 5.4 используйте \Illuminate\Database\Schema\Builder::defaultStringLength(191);правильный путь ссылки на функцию
webcoder

5
После настройки в AppServiceProvider.php эта проблема все еще возникает. Я просто запутался. Зачем? Я перезапустил сервер, базу данных и все, но все еще. Пожалуйста помоги.
Кушик дас

3
Вы должны установить длину индексированного столбца в соответствии с лимитом 767 байт. Помните, что VARCHAR может иметь 1, 2 или 4 байта для каждой единицы длины. Пример: utf8_mb4 (4 байта) -> 767/4 = 191. В противном случае utf8_general_ci для VARCHAR (X) с X <85 (1 байт) = O (85) или utf8_general_ci для VARCHAR (X) с X> = 86 (2) bytes) -> 767/2 = 383. Рассмотрим также длину других столбцов в индексах с несколькими столбцами.
Джеки

2
Возможно, вы также захотите изменить длину конкретного столбца в файлах миграции, указав длину по умолчанию для всех строковых столбцов, поскольку не всем столбцам потребуется это ограничение, поскольку они отсутствуют в индексе. $ table-> строка ( 'column_name', 191);
Джеки

109

Обновление 1

Начиная с Laravel 5.4, эти изменения больше не нужны.

Laravel 5.4 использует набор символов utf8mb4 по умолчанию, который включает поддержку для хранения «emojis» в базе данных. Если вы обновляете свое приложение с Laravel 5.3, вам не нужно переключаться на этот набор символов.

Обновление 2

Текущие производственные версии MariaDB НЕ поддерживают эту настройку по умолчанию во всем мире. Он реализован в MariaDB 10.2.2+ по умолчанию .

Решение

И если вы намеренно хотите использовать правильную многобайтовую utf8mb4поддержку UTF8 для будущих значений по умолчанию (начиная с Laravel 5.4), то начните исправлять конфигурацию базы данных.

В Laravel config/database.phpопределяют:

'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'engine' => 'InnoDB ROW_FORMAT=DYNAMIC',

DYNAMICпозволяет хранить длинные ключевые индексы.

Настройки сервера (по умолчанию включены в MySQL 5.7.7+ / MariaDB 10.2.2+):

[mysqld]
# default character set and collation
collation-server = utf8mb4_unicode_ci
character-set-server = utf8mb4

# utf8mb4 long key index
innodb_large_prefix = 1
innodb_file_format = barracuda
innodb_file_format_max = barracuda
innodb_file_per_table = 1

Для клиентов:

[mysql]
default-character-set=utf8mb4

А затем ОСТАНОВИТЕ свой сервер MySQL / MariaDB. После этого СТАРТ. Горячая перезагрузка может не работать.

sudo systemctl stop mysqld
sudo systemctl start mysqld

Теперь у вас есть Laravel 5.x с поддержкой UTF8.


3
Это может хорошо работать с MySQL 5.5 (не пытался перенастроить). 5.7 (вероятно, также 5.6) работали без какой-либо реконфигурации. 5.7 был дистрибутивом Сервера совместной работы по умолчанию с ванильной конфигурацией.
Петр

Я изменил движок в моем database.php, как вы упомянули, но он все еще создает таблицы с row = compact, что вызывает проблему. Я не совсем понял, вы говорите, что недостаточно внести это изменение в database.php и что также необходимо внести изменения в файл my.cnf?
vesperknight

Достаточно внести изменения только в database.phpконфигурационном файле, и это повлияет на локальный проект Laravel. Обязательно внесите deleteбазу данных перед внесением изменений и создайте ее с новыми настройками. Вам необходимо изменить my.cnfконфигурационный файл только для глобальных изменений на стороне сервера (в настоящее время используются все новые установки utf8mb4).
бомбардир

Или - добавьте другое поле, вычислите хэш электронной почты, сделайте поле уникальным, навсегда решите проблему, избегайте использования переменных инициализации базы данных.
NB

Если кто-то использует Doctrine 2 , вы можете установить ROW_FORMAT, перейдя options={"row_format"="DYNAMIC"}к @Tableаннотации.
Albert221

50

Если вы работаете с Laravel 5.4 или обновились до него, это сработало для меня;

Всего 1 смена. в AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

public function boot()
{
  Schema::defaultStringLength(191);
}

Как упоминалось в руководстве по миграции, https://laravel.com/docs/master/migrations#creating-indexes


Я сделал это на самой миграции.
Амирмасуд

7
Это (предположительно), потому что каждый символ занимает ровно 4 байта, а максимальная длина ключа измеряется в байтах, а не символах. Таким образом, длина ключа будет на 191 * 4 = 764 байта, просто smidgen под максимальными 767 байтами, которые будет поддерживать база данных. Решения нуждаются в объяснениях IMO, если они хотят внести свой вклад в обмен знаниями здесь, а не просто предоставить «процедуры». Но удобное решение тем не менее.
Джейсон

33

Если кто-то еще наткнется на этот ответ, как я, но по другой причине, вы можете проверить кодировку / сопоставление Laravel DB.

Я устанавливал приложение (Snipe-IT) и настроил конфигурацию базы данных Laravel для использования следующего:

'charset' => 'utf8mb4',
'collation' => 'utf8mb4_general_ci',

Удаление mb4из обеих строк решило проблему, хотя я считаю, что ответ Антонио - реальное решение проблемы.



16

Удалите mb4 из charset и параметры сортировки из config / database.php, тогда он будет успешно выполнен.
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',


15

Для Laravel 5.6
Это решение решить мою проблему
перейдите к config/database.php
Найти код ниже

'mysql' => [
    'driver' => 'mysql',
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'forge'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'unix_socket' => env('DB_SOCKET', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'strict' => true,
    'engine' => null,
],

Изменить это два поля

'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci'

С этим

'charset' => 'utf8',
'collation' => 'utf8_unicode_ci'

14

Я столкнулся с той же проблемой и исправил ее, добавив две строки ниже в мой app / database.php

'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',

Мой файл выглядит следующим образом:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Default Database Connection Name
    |--------------------------------------------------------------------------
    |
    | Here you may specify which of the database connections below you wish
    | to use as your default connection for all database work. Of course
    | you may use many connections at once using the Database library.
    |
    */

    'default' => env('DB_CONNECTION', 'mysql'),

    'charset' => 'utf8',
    'collation' => 'utf8_unicode_ci',

    ......

2
Если вы установили новую версию в Laravel. Удалите 'mb4' из utf8mb4 & utf8mb4_unicode_ci & config / database.php
Muthu17

13

Для laravel 5.4 просто отредактируйте файл

App \ провайдеры \ AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

public function boot()
{
    Schema::defaultStringLength(191);
}

7
File: config/database.php
change the following
FROM ->
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',

TO ->
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',

1
Хотя это может ответить на вопрос, лучше добавить описание того, как этот ответ может помочь решить проблему. Пожалуйста, прочитайте Как мне написать хороший ответ, чтобы узнать больше.
Рошана Питигала

6

У меня была такая же проблема, и я использую Wamp

Решение: Откройте файл: config / database.php

'engine' => null, => 'engine' => 'InnoDB',

Спасибо


Ни один из предыдущих ответов не сработал для меня, но этот сработал как шарм! И это имеет смысл, я считаю, что в предыдущих версиях движка Laravel DB по умолчанию был установлен InnoDB, поэтому мы не сталкивались с этими ошибками ранее.
Саша Благоевич

да нужно было сделать пару других ответов и это тоже.
Андрей

6

В файле config / database.php, где:

'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',

Измените эту строку на эту:

'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',

5

Для Laravel> = 5.6 пользователей

Открыть AppServiceProvider.phpфайл

Используйте следующий класс

use Illuminate\Support\Facades\Schema;

Затем внутри bootметода добавьте следующую строку

public function boot()
{
    Schema::defaultStringLength(191);
}

4

Я добавил к самой миграции

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

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


4

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

namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;

class AppServiceProvider extends ServiceProvider
{
  /**
   * Register any application services.
   *
   * @return void
   */
   public function register()
   {
      //
   }

   public function boot()
   {
     Schema::defaultStringLength(191);
   }
}

Но это не сработает сразу по двум причинам. Во-первых, если вы используете lumen вместо laravel, вам, возможно, придется сначала раскомментировать эту строку в файле app.php.

$app->register(App\Providers\AppServiceProvider::class);

А затем вам нужно снова создать сценарий миграции с помощью команды ремесленника,

php artisan make:migration <your_table_name>

Поскольку теперь будут работать только те изменения, которые вы внесли в ServiceProvider.


4

для laravel 5.7 напишите этот код в appserviceprovider.php

  use Illuminate\Support\Facades\Schema;

public function boot()
{
  Schema::defaultStringLength(191);
}

2

Измените кодировку с utf8mb4 на utf8 и

сопоставление 'utf8mb4_unicode_ci' с 'utf8_unicode_ci'

в файле config / database.php

Это сработало для меня.


2

Laravel использует utf8mb4набор символов по умолчанию, который включает в себя поддержку хранения «emojis» в базе данных. Если вы используете версию MySQL, более раннюю, чем версия 5.7.7, или MariaDB, более раннюю, чем версия 10.2.2, вам может потребоваться вручную настроить длину строки по умолчанию, генерируемую миграциями, чтобы MySQL создавал для них индексы. Вы можете настроить это, вызвав Schema::defaultStringLengthметод в вашем AppServiceProvider:

use Illuminate\Support\Facades\Schema;

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

Вы можете проверить из

https://laravel-news.com/laravel-5-4-key-too-long-error https://laravel.com/docs/5.5/migrations#indexes


спасибо, у меня работает. Mamp MySQL с Laravel 5.6.23
Bluesky

2

Это потому, что Laravel 5.4 использует utf8mb4, который поддерживает хранение эмодзи.

Добавьте это в ваше приложение \ Providers \ AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

public function boot()
{
    Schema::defaultStringLength(191);
}

и тебе должно быть хорошо идти.


2

Если вы используете или обновили Laravel 5.4 и последнюю версию, это работает;
Всего 1 изменение в AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

public function boot()
{
  Schema::defaultStringLength(191);
}

1

Я хотел бы указать на то, что я пропустил ...

Я новичок в Laravel, и я не копировал «использовать Illuminate .....», потому что я действительно не уделил этому внимание, потому что прямо над загрузкой функции, которую вы уже прочитали, есть оператор использования .

Надеюсь, это поможет кому-нибудь

**use Illuminate\Support\Facades\Schema;**

public function boot()
{
    Schema::defaultStringLength(191);
}

Вы также можете просто \
добавить

1

У меня возникла проблема, измените конфигурацию «config / database»

file 'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',

сохраняя тот же шаблон в базе данных.

Затем я дал команду

php artisan migrate

1

24 октября 2016 года Тейлор Отвелл, автор Laravel, объявил в твиттере

«utf8mb4» будет набором символов MySQL по умолчанию в Laravel 5.4 для лучшей поддержки смайликов. Twitter Тейлор Отвелл пост в Твиттере

который до версии 5.4 набор символов был utf8

В течение этого столетия многие веб-приложения включали чат или какую-то платформу, позволяющую пользователям общаться, и многим людям нравится использовать смайлики или смайлики. и это своего рода супер-символы, которые требуют больше места для хранения, и это возможно только при использовании utf8mb4в качестве кодировки . Это причина, почему они мигрируют utf8mb4только для космических целей.

если вы посмотрите вверх в Illuminate\Database\Schema\Builderклассе, то увидите, что для $defaultStringLengthнего установлено значение 255 , и для его изменения вы можете пройти через SchemaФасад, вызвать defaultStringLengthметод и передать новую длину.

чтобы выполнить это изменение, вызовите этот метод в вашем AppServiceProviderклассе, который находится в подкаталоге app \ provider, например:

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        // all other code ...

        Schema::defaultStringLength(191); 
    }
    // and all other code goes here
}

Я предложу использовать 191 в качестве значения только потому, что MySQL поддерживает 767 байтов, и потому 767 / 4что это число байтов, которое получает каждый многобайтовый символ, который вы получите 191.

Вы можете узнать больше здесь Ограничения набора символов utf8mb4 (4-байтовое кодирование Unicode UTF-8) для числа столбцов таблицы и размера строки


Это единственный ответ, который объясняет 191магическое число.
Илья Москвин

1

РЕШЕНИЕ:

Сначала измените defaultStringLength на 191 в app \ Providers \ AppServiceProvider.php :

public function boot()
{
    Schema::defaultStringLength(191);
}

Затем измените значения набора символов и параметров сортировки следующим образом в config \ database.php :

'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',

( ссылка, чтобы узнать о MariaDB charset )


1

Перейдите к своему config/database.phpи измените кодировку и сопоставление с utf8mb4 на utf8

'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',

Моя проблема решена с помощью этого метода, удачи, чувак!


0

У вас не будет этой проблемы, если вы используете MySQL 5.7.7+ или MariaDB 10.2.2+.

Чтобы обновить MariaDB на вашем Mac с помощью Brew, сначала отсоедините текущую версию, brew unlink mariadbа затем установите dev, используяbrew install mariadb --devel

После завершения установки остановите / запустите службу: brew services stop mariadb brew services start mariadb

Текущая версия - 10.2.3. После завершения установки вам больше не придется беспокоиться об этом, и вы можете использовать utf8mb4 (который теперь используется по умолчанию в Laravel 5.4), не переключаясь обратно на utf8 и не редактируя AppServiceProvider, как предлагается в документации Laravel: https: // laravel .com / docs / master / release # laravel-5.4 (прокрутите вниз до: Длина строки миграции по умолчанию )


0

Только что установил MariaDB 10.2.4 RC, запустил новый пустой проект Laravel 5.4 и работает миграция по умолчанию (столбцы varchar (255)).

Не нужно менять БД conf и Laravael config/database.php. Таким образом, так же, как @scorer отметил поведение по умолчанию для 10.2.2+.


0

Все было хорошо описано в других Anwser, более подробную информацию вы можете увидеть в ссылке ниже (поиск по ключу «Длина индекса и MySQL / MariaDB») https://laravel.com/docs/5.5/migrations

НО ХОРОШО, ЭТО НЕ О ЧЕМ ЭТО ОТВЕТ дело даже в том, что, выполнив вышесказанное, вы захотите получить еще одну ошибку (вот когда вам нравится php artisan migrateкоманда запуска и из-за проблемы длины, операция, как застрявшая посередине. решение ниже , и пользовательская таблица, как создается без остальное или не совсем правильно) нам нужно накатить бак к. откат по умолчанию не подойдет. потому что операция по миграции не понравилась закончить. Вам необходимо удалить новые созданные таблицы в базе данных вручную.

мы можем сделать это с помощью повозки, как показано ниже:

L:\todos> php artisan tinker

Psy Shell v0.8.15 (PHP 7.1.10  cli) by Justin Hileman

>>> Schema::drop('users')

=> null

У меня самого была проблема с таблицей пользователей.

после этого ты можешь идти

php artisan migrate:rollback

php artisan migrate

0

Установить движок базы данных InnoDB:

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

0

Если вы попробовали все остальные ответы, но они не сработали, вы можете удалить все таблицы из базы данных, а затем сразу выполнить команду migrate, используя эту команду:

php artisan migrate:fresh
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.