Ошибка миграции Laravel: синтаксическая ошибка или нарушение прав доступа: 1071 Указанный ключ слишком длинный; максимальная длина ключа 767 байт

178

Ошибка миграции на Laravel 5.4 с php artisan make:auth

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

[PDOException] SQLSTATE [42000]: синтаксическая ошибка или нарушение доступа: 1071 Указанный ключ слишком длинный; максимальная длина ключа 767 байт

absiddiqueLive
источник
3
Вы должны ответить на свой вопрос в ответе. Не в этом вопросе. stackoverflow.com/help/self-answer
Can Vural
Спасибо за предложение @ can-vural, я сделал.
absiddiqueLive

Ответы:

283

Согласно официальной документации , вы можете решить это довольно легко.

Добавьте следующие две строки кода в AppServiceProvider.php (/app/Providers/AppServiceProvider.php).

use Illuminate\Database\Schema\Builder; // Import Builder where defaultStringLength method is defined

function boot()
{
    Builder::defaultStringLength(191); // Update defaultStringLength
}

MySQL всегда резервирует максимальную сумму для поля UTF8, которая составляет 4 байта, поэтому при 255 + 255 с вашим SET DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; Вы превысили максимальную длину ключа 767 @Scaisedge

absiddiqueLive
источник
3
Будьте осторожны с этим решением. Например, если вы индексируете поля электронной почты, хранимые электронные письма могут иметь максимальную длину 191 символа. Это меньше, чем заявляет официальный RFC.
shock_gone_wild
1
Это решение предложено Laravel github.com/laravel/framework/issues/17508 laracasts.com/discuss/channels/laravel/…
absiddiqueLive
Это работает и является правильным решением, но я просто хотел отметить, что при таком подходе возможны подводные камни.
shock_gone_wild
Я надеюсь, что это решение не сможет укусить меня за задницу в будущем, но сейчас это работает. Я должен быть осторожен с тем, как я индексирую электронные письма все же.
deusofnull
4
почему именно 191 символ @absiddiqueLive
PseudoAj
121

Я не знаю, почему вышеупомянутое решение и официальное решение, которое добавляет

Schema::defaultStringLength(191);

в AppServiceProvider меня не получилось. То, что работало для редактирования database.phpфайла в configпапке. Просто отредактируйте

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

в

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

и это должно работать, хотя вы не сможете хранить расширенные многобайтовые символы, такие как эмодзи .

Я сделал это с Laravel 5.7. Надеюсь, поможет.

Кушик дас
источник
5
Использование этого набора символов позволит вам сохранить только стандартные ASCII, а не многобайтовые специальные символы, такие как символы из арабского языка, иврита, большинства европейских сценариев и, конечно, смайликов. см. также stackoverflow.com/a/15128103/4233593
Джефф
7
Я думаю, что вы пропустили эту часть use Illuminate\Support\Facades\Schema;наверху.
pimpace
@KoushikDas, какую версию Laravel вы используете?
pimpace
Сейчас я на 6.0. Я думаю, что я сделал это изначально с 5,7 или 5,6, может быть.
Кушик дас
2
utf8mb4Сличение есть по причине, я рекомендую использовать его , если вы можете.
Пламя
85

Я просто добавляю этот ответ здесь, поскольку это quickestрешение для меня. Просто установите ядро ​​базы данных по умолчанию 'InnoDB'на

/config/database.php

'mysql' => [
    ...,
    ...,
    'engine' => 'InnoDB',
 ]

затем запустите, php artisan config:cacheчтобы очистить и обновить кеш конфигурации

Декстер Бенгил
источник
1
Это должен быть официальный ответ / решение этого вопроса ... Спасибо
Syamsoul Azrien
1
Это фактическое решение, другие обходные пути
Луис Кунья
3
но какая логика стоит за этим
Зульфикар Тарик
1
Это правильное решение. Но почему бы не включить его в установку по умолчанию.
Анкит Чаухан
38

В AppServiceProvider.php, включить этот код верхней части файла.

use Illuminate\Support\Facades\Schema;

public function boot()
{
Schema::defaultStringLength(191);
}
user7688086
источник
Спасибо, выручил меня
Мертвец
24

Эта проблема вызвана в Laravel 5.4 версией базы данных.

Согласно документацииIndex Lengths & MySQL / MariaDBразделе):

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

Другими словами, в <ROOT>/app/Providers/AppServiceProvider.php:

// Import Schema
use Illuminate\Support\Facades\Schema;
// ...

class AppServiceProvider extends ServiceProvider
{

public function boot()
{
    // Add the following line
    Schema::defaultStringLength(191);
}

// ...

}

Но, как говорится в комментарии к другому ответу:

Будьте осторожны с этим решением. Например, если вы индексируете поля электронной почты, хранимые электронные письма могут иметь максимальную длину 191 символа. Это меньше, чем заявляет официальный RFC.

Таким образом, документация также предлагает другое решение:

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

Эстебан Эррера
источник
16

Для тех, кто не хочет меняться AppServiceProvider.php. (На мой взгляд, это плохая идея, чтобы изменить AppServiceProvider.phpтолько для миграции)

Вы можете добавить обратно длину данных в файл миграции, database/migrations/как показано ниже:

create_users_table.php

$table->string('name',64);
$table->string('email',128)->unique();

create_password_resets_table.php

$table->string('email',128)->index();
helloroy
источник
Это может быть проблемой, поскольку электронные письма могут содержать до 255 символов
наполовину
Вы правы @HalfCrazed, но я предлагаю этот ответ stackoverflow.com/questions/1297272
helloroy
моя проблема была точно решена этим решением. Мои поля не были электронными письмами.
Тарака Девинда
11

Если вы столкнулись с этой ошибкой во время работы над laravel при использовании команды: php artisan migrate просто добавьте в файл 2 строки: app-> Providers-> AppServiceProvider.php

  1. use Schema;
  2. Schema::defaultStringLength(191);

пожалуйста, проверьте это изображение . затем php artisan migrateснова запустите команду.

Абдул Рашид
источник
1
очень важно добавить 'использовать схему;' Так что это лучший ответ
hxwtch
Вы также можете сделать это в одну строку, добавив обратную косую черту '\' перед 2-й строкой, как это\Schema::defaultStringLength(191);
Tahir Afridi
10

Я добавляю два решения, которые работают для меня.

1-е растворение это :

  1. Откройте файл database.php insde config dir / folder.
  2. Изменить 'engine' => null,на'engine' => 'InnoDB',

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

2-е решение:

  1. Откройте файл database.php insde config dir / folder.
    2. Изменить
    'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci',
    на

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


Удачи

Арслан Ахмад
источник
10

обновите и вставьте эти строки в app / Providers / AppServiceProvider.php

use Illuminate\Support\Facades\Schema;  // add this line at top of file

public function boot()
{
    Schema::defaultStringLength(191); // add this line in boot method
}
Анджани Барнвал
источник
8

Я решил эту проблему и отредактировал файл config-> database.php так, чтобы он соответствовал моей базе данных ('charset' => 'utf8') и ('collation' => 'utf8_general_ci') , поэтому моя проблема решена как следовать:

'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' => 'utf8',
        'collation' => 'utf8_general_ci',
        'prefix' => '',
        'strict' => true,
        'engine' => null,
    ],
Ахмад Шакиб
источник
8

Я нашел два решения этой ошибки

ОПЦИЯ 1:

Откройте таблицу user и password_reset в папке database / migrations

И просто измените длину письма:

$table->string('email',191)->unique();

ВАРИАНТ 2:

Откройте ваш app/Providers/AppServiceProvider.phpфайл и внутри boot()метода установите длину строки по умолчанию:

use Illuminate\Support\Facades\Schema;

public function boot()
{
    Schema::defaultStringLength(191);
}
Удхав Сарваия
источник
7

1- иди /config/database.phpи найди эти строки

'mysql' => [
    ...,
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    ...,
    'engine' => null,
 ]

и измените их на:

'mysql' => [
    ...,
    'charset' => 'utf8',
    'collation' => 'utf8_unicode_ci',
    ...,
    'engine' => 'InnoDB',
 ]

2- Беги, php artisan config:cacheчтобы перенастроить Laravel

3- Удалите существующие таблицы в вашей базе данных, а затем php artisan migrateснова запустите

Мохаммад Асгари
источник
1
это лучший ответ для Laravel 5.8. Но удалите уже созданные таблицы
Magige Daniel
но согласно документации "utf8" будет использовать устаревший режим utf8?
NoBugs
5

В файле AppServiceProvider.php :

 use Illuminate\Support\Facades\Schema;

public function boot()
{
    Schema::defaultStringLength(191);
}
Уддян Семвал
источник
5

Вместо того, чтобы устанавливать ограничение по длине, я бы предложил следующее, что сработало для меня.

Внутри:

конфиг / database.php

замените эту строку для mysql:

'engine' => 'InnoDB ROW_FORMAT=DYNAMIC',

с участием:

'engine' => null,
Md. Noor-A-Alam Siddique
источник
4

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

use Illuminate\Support\Facades\Schema;

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

Примечание: сначала вы должны удалить (если есть) таблицу пользователей, таблицу password_resets из базы данных и удалить записи пользователей и password_resets из таблицы миграции .

Чтобы выполнить все ваши выдающиеся миграции, выполните команду migrateArtisan:

php artisan migrate

После этого все должно работать как обычно.

Декстер Бенгил
источник
4

Как уже было указано, мы добавляем AppServiceProvider.php в App / Providers.

use Illuminate\Support\Facades\Schema;  // add this

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

Вы можете увидеть более подробную информацию в ссылке ниже (поиск "Длина индекса и 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

Мохаммед Аллал
источник
4

Решение, о котором никто не говорит, состоит в том, что в Mysql v5.5 и более поздних версиях InnoDB является механизмом хранения по умолчанию, у которого нет этой проблемы, но во многих случаях, как у меня, есть некоторые старые файлы конфигурации mysql ini, которые используют старый механизм хранения MYISAM, как показано ниже.

default-storage-engine=MYISAM

который создает все эти проблемы, и решение состоит в том, чтобы раз и навсегда изменить механизм хранения по умолчанию на InnoDB в файле конфигурации ini Mysql вместо временного взлома.

default-storage-engine=InnoDB

И если вы используете MySql v5.5 или новее, то InnoDB - это движок по умолчанию, поэтому вам не нужно устанавливать его явно, как описано выше, просто удалите его, default-storage-engine=MYISAMесли он существует, iniи все готово.

Али А. Диллон
источник
Спасибо! Мне пришлось использовать это предложение в сочетании с изменениями длины строки, набора символов и параметров сортировки, чтобы заставить его работать с laravel 6 и mysql 5.6. Надеюсь, это поможет другим в будущем.
Каспер Уилкс
@CasperWilkes, тебе не нужно ничего делать с этой длиной строки, кодировка. Проверьте системную переменную Mysql следующим образом: show global variables like 'innodb_large_prefix';она должна быть включена . Если он выключен, вы можете проверить этот ответ о том, как его включить. А вот больше информации о innodb_large_prefix на dev.mysql.com.
Али А. Диллон
3

Если вы хотите изменить в AppServiceProvider, то вам нужно определить длину поля электронной почты при миграции. просто замените первую строку кода на вторую строку.

create_users_table

$table->string('email')->unique();
$table->string('email', 50)->unique();

create_password_resets_table

$table->string('email')->index();
$table->string('email', 50)->index();

После успешных изменений вы можете запустить миграцию.
Примечание: сначала необходимо удалить (если есть) пользователи таблицы , таблицы password_resets из базы данных и удаления пользователей и password_resets записей из таблицы миграции.

Чинтан Котадия
источник
3

Schema::defaultStringLength(191);по умолчанию определит длину всех строк 191, что может испортить вашу базу данных. Вы не должны идти по этому пути.

Просто определите длину любого конкретного столбца в классе миграции базы данных. Например, я определяю «имя», «имя пользователя» и «адрес электронной почты» в CreateUsersTableклассе, как показано ниже:

public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name', 191);
            $table->string('username', 30)->unique();
            $table->string('email', 191)->unique();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }
Фатема Т. Зухора
источник
1
Это наиболее предпочтительно для меня, так как я бы не стал подправлять какие-либо основные коды Laravel.
Okiemute Omuta
2

Это часто встречается, поскольку Laravel 5.4 изменил установленный по умолчанию характер базы данных на utf8mb4. Что вы должны сделать, это: отредактируйте ваш App \ Providers.php, поместив этот код перед объявлением класса

use Illuminate\Support\Facades\Schema;

Кроме того, добавьте это в функцию «загрузки» Schema::defaultStringLength(191);

сокровище
источник
2

Если у вас нет данных, уже назначенных вашей базе данных, сделайте следующее:

  1. Перейдите в app / Providers / AppServiceProvide.php и добавьте

использовать Illuminate \ Support \ ServiceProvider;

и внутри метода boot ();

Схема :: defaultStringLength (191);

  1. Теперь удалите записи в вашей базе данных, например, пользовательскую таблицу.

  2. запустить следующее

Конфигурация PHP Artisan: кэш

php ремесленник мигрировать

Левинский польский
источник
Это сработало, но нужно добавить use Illuminate\Support\Facades\Schema; use Illuminate\Support\ServiceProvider;уже есть. Надеюсь, вы исправите это
Джимиш Гамит
2

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

//edit your AppServiceProvider.php file contains in providers folder
use Illuminate\Support\Facades\Schema;

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

Надеюсь, это поможет вам .. ура ..

Рохит Сайни
источник
2

Я только что изменил следующую строку usersи password_resetsфайл миграции.

Старый: $table->string('email')->unique();

Новый: $table->string('email', 128)->unique();

Махеш Гайквад
источник
1

Чтобы ничего не менять в вашем коде , просто обновите сервер MySQL как минимум до 5.7.7

Ссылка на это для получения дополнительной информации: https://laravel-news.com/laravel-5-4-key-too-long-error

ИП Ноэль Нфебе
источник
Нет, Mariadb 10.1.41 в 18.04 также имеет эту ошибку.
NoBugs
1

Я думаю, что заставить StringLenght на 191 действительно плохая идея. Поэтому я расследую, чтобы понять, что происходит.

Я заметил, что это сообщение об ошибке:

SQLSTATE [42000]: синтаксическая ошибка или нарушение доступа: 1071 Указанный ключ был слишком длинным; максимальная длина ключа 767 байт

Начал появляться после того, как я обновил свою версию MySQL. Поэтому я проверил таблицы с помощью PHPMyAdmin и заметил, что все новые таблицы были созданы с сопоставлением utf8mb4_unicode_ci вместо utf8_unicode_ci для старых.

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

Теперь несложное решение - изменить линейный набор символов в вашем конфигурационном файле ORM. Затем удалите таблицы с помощью utf8mb4_unicode_ci, если вы находитесь в режиме разработки, или исправьте кодировку, если вы не можете их удалить.

Для Symfony 4

изменить кодировку: utf8mb4 на кодировку: utf8 в config / packages / doctrine.yaml

Теперь мои доктрины миграции снова работают хорошо.

Kaizoku Gambare
источник
1

Рекомендуемое решение - включить innodb_large_prefixопцию MySQL, чтобы избежать последующих проблем. И вот как это сделать:

Откройте my.iniфайл конфигурации MySQL и добавьте ниже строки под [mysqld]строкой, как это.

[mysqld]
innodb_file_format = Barracuda
innodb_large_prefix = 1
innodb_file_per_table = ON

После этого сохраните изменения и перезапустите службу MySQL.

Откат, если вам нужно, а затем повторно запустите миграцию.


На случай, если проблема не устранена, перейдите в файл конфигурации базы данных и установите

'engine' => null, в 'engine' => 'innodb row_format=dynamic'

Надеюсь, поможет!

Сэмми
источник
1

сначала удалите все таблицы базы данных на локальном хосте

Измените свойства базы данных Laravel по умолчанию (utf8mb4) в файле config / database.php на:

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

после этого изменив свойства моей локальной базы данных utf8_unicode_ci. php artisan migrate это нормально.

Goldman.Vahdettin
источник
0

Для всех, кто мог столкнуться с этим, моя проблема заключалась в том, что я делал столбец типа stringи пытался создать его, ->unsigned()когда хотел, чтобы он был целым числом.

Бринн Бейтман
источник
0

Подходя к этой работе, здесь передают второй параметр с ключевым именем (коротким):

$table->string('my_field_name')->unique(null,'key_name');
Тиаго Гувеа
источник
0

Я получал эту ошибку, хотя у меня уже было (на самом деле, потому что у меня уже было) Schema :: defaultStringLength (191); в моем файле AppServiceProvider.php.

Причина в том, что я пытался установить строковое значение в одной из моих миграций на значение выше 191:

Schema::create('order_items', function (Blueprint $table) {
    $table->primary(['order_id', 'product_id', 'attributes']);
    $table->unsignedBigInteger('order_id');
    $table->unsignedBigInteger('product_id');
    $table->string('attributes', 1000); // This line right here
    $table->timestamps();
});

Удаление 1000 или установка 191 решило мою проблему.

Jacey
источник