Міграція 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');
});

Після деякого гуглінгу я натрапив на цей звіт про помилку, де Тейлор каже, що ви можете вказати індексний ключ як другий параметр unique(), який я зробив. Це все ще дає помилку. Що тут відбувається?


Чому ви використовуєте 320 символів для електронної пошти? Це може бути вашою проблемою.
Антоніо Карлос Рібейро

1
Це справді була проблема, не знаю чому. Але так, ви праві, я не знаю, чому я вказав довжину знака для кожного поля.
Зняли

Смішно, як ніхто не запропонував використовувати поле фіксованої довжини, яке містить хеш електронної пошти та вуаля - проблема, вирішена назавжди, для будь-якої основи та будь-якої реляційної бази даних. Тому що ми гарантуємо унікальність - використовуючи фіксовану кількість введення змінної довжини, враховуючи той факт, що діапазон чисел досить великий (і для sha1 / sha256 це).
NB

1
laravel-news.com/laravel-5-4-key-too-long-error може отримати допомогу
манікт

Відповіді:


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 байт) -> 767/2 = 383. Розгляньте також інші стовпці довжиною у кількох індексах стовпців.
Jackie Degl'Innocenti

2
Ви також можете безпосередньо відредагувати довжину конкретного стовпця у файлах міграції, вказавши довжину за замовчуванням для всіх стовпців рядків, оскільки не всі стовпці потребуватимуть цього обмеження, оскільки їх немає в жодному індексі. $ table-> string ('ім'я_колонки', 191);
Jackie Degl'Innocenti

109

Оновлення 1

Станом на Laravel 5.4 ці зміни більше не потрібні.

Laravel 5.4 використовує набір символів utf8mb4 за замовчуванням, що включає підтримку зберігання "емоджи" в базі даних. Якщо ви оновлюєте свою програму з Laravel 5.3, вам не потрібно переходити до цього набору символів.

Оновлення 2

Поточні виробничі версії MariaDB НЕ підтримують цей параметр за замовчуванням у всьому світі. Він реалізований у MariaDB 10.2.2+ за замовчуванням .

Рішення

І якщо ви навмисно хочете використовувати правильний майбутній за замовчуванням (починаючи з Laravel 5.4) UTF8 багатобайтну utf8mb4підтримку 😀, тоді почніть виправляти 😂 конфігурацію вашої бази даних.

У 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. Після цього СТАРТ. Гарячий RESTART може не працювати.

sudo systemctl stop mysqld
sudo systemctl start mysqld

Тепер у вас є Laravel 5.x з підтримкою UTF8.


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

Як я вже згадував, я змінив двигун у своїй базі даних data.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


Я зробив це на самій міграції.
Amirmasoud

7
Це (імовірно), оскільки кожен символ займає рівно 4 байти, а максимальна довжина ключа вимірюється в байтах, а не символах. Таким чином, довжина ключа буде на 191 * 4 = 764 байт, просто smidgen під максимальними 767 байтами, які підтримуватиме база даних. Рішення потребують пояснень IMO, якщо вони хочуть внести свій внесок у спільне знання тут, а не просто забезпечити "процедури". Але зручне виправлення все-таки.
Джейсон

33

Якщо хтось інший натрапляє на цю відповідь, як я, але з іншої причини, ви можете перевірити свій Laravel DB-набір / порівняння.

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

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

Видалення mb4з обох рядків фіксованих питання, хоча я вважаю , відповідь Антоніо є реальним вирішенням проблеми.



16

Видаліть mb4 з набору даних і порівняння з 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

Я зіткнувся з тією ж проблемою і вирішив її, додавши нижче два рядки в моє додаток / 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 просто відредагуйте файл

Додаток \ Постачальники \ 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

У мене була така ж проблема, і я використовую вамп

Рішення: Відкрити файл: config / database.php

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

Дякую


Жодна з попередніх відповідей не працювала для мене, але ця працювала як шарм! І це має ідеальний сенс, я вважаю, що в попередніх версіях двигуна DB Laravel було встановлено 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);
   }
}

Але це не вийшло відразу з двох причин. Одне з них - якщо ви використовуєте просвіт замість 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набір символів за замовчуванням, який включає підтримку зберігання "емоджи" в базі даних. Якщо ви використовуєте версію 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, який підтримує зберігання емоджи .

Додайте це у свою програму \ Постачальники \ 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, і я не копіював "use 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, повідомив у Twitter

"utf8mb4" буде символом MySQL за замовчуванням, встановленим у Laravel 5.4 для кращої підтримки емоджи. 🙌 Тейлор Оттуел у Twitter

який до версії 5.4 був набором символів utf8

Протягом цього століття багато веб-додатків, включають чат або якусь платформу, яка дозволяє їх користувачам переходити, і багато людей люблять використовувати смайли або смайлик. і це якісь супер символи, яким потрібно зберігати більше місця, і це можливо лише utf8mb4в якості шаблону . Саме тому вони переходять на utf8mb4просто космічні цілі.

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

виконувати цей виклик зміни цього AppServiceProviderкласу у вашому класі, який знаходиться у підкаталозі додаток \ провайдери, як цей

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-байтове кодування UTF-8 Unicode) на кількість стовпців таблиці та розмір рядка


Це єдина відповідь, яка пояснює 191магічне число.
Ілля Москвін

1

РІШЕННЯ:

Спочатку змініть defaultStringLength на 191 у додатку \ Провайдери \ AppServiceProvider.php :

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

Потім змініть значення діаграми та зіставлення наступним чином у config \ database.php :

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

( посилання, щоб знати про charset MariaDB )


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а потім встановіть розробник за допомогою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)).

Не потрібно змінювати конфіденційну базу даних та Laravael config/database.php. Таким чином, як @scorer відзначав поведінку за замовчуванням для 10.2.2+.


0

Все було добре описано в інших програмах Anwser. Докладніші відомості ви можете побачити нижче за посиланням (пошук за допомогою клавіші "Індекс довжини та MySQL / MariaDB") https://laravel.com/docs/5.5/migrations

Але НЕ БУДЕ, що це не відповідь! справа навіть у виконанні вищесказаного вам сподобається отримати ще одну помилку (саме тоді вам подобається php artisan migrateкоманда запуску і через проблему довжини, операція, як застрягла в середині. Рішення нижче , а таблиця користувачів, як створена без решта чи не зовсім коректно) нам потрібно прокатати bac k. відкат за замовчуванням не буде робити. тому що операція міграції не любила закінчувати. вам потрібно видалити нові створені таблиці в базі даних вручну.

ми можемо це зробити, використовуючи тинкер, як показано нижче:

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.