Помилка міграції Laravel: помилка синтаксису або порушення доступу: 1071 Вказаний ключ був занадто довгим; Максимальна довжина ключа - 767 байт


178

Помилка міграції на Laravel 5.4 с php artisan make:auth

[Illuminate \ Database \ QueryException] SQLSTATE [42000]: Помилка синтаксису або порушення доступу: 1071 Зазначений ключ був занадто довгим; Максимальна довжина ключа - 767 байт (SQL: змінити tabl і usersдодати унікальний users_email_unique( email))

[PDOException] SQLSTATE [42000]: Помилка синтаксису або порушення доступу: 1071 Вказаний ключ був занадто довгим; Максимальна довжина ключа - 767 байт


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 з вашим набором DEFAULT CHARACTER utf8mb4 COLLATE utf8mb4_unicode_ci; ви перевищили максимальну межу довжини ключа 767 За @scaisedge


3
Будьте уважні до цього рішення. Якщо, наприклад, індексувати поля електронної пошти, збережені електронні листи можуть мати максимум довжину 191 символу. Це менше, ніж офіційні держави RFC.
shock_gone_wild


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

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
Це власне рішення, інші вирішують проблеми
Luís Cunha

3
але яка логіка цього
Zulfiqar Tariq

1
Це правильне рішення. Але чому б він не був включений у встановлення за замовчуванням.
Анкіт Чаухан

38

У розділі AppServiceProvider.phpви додаєте цей код у верхній частині файлу.

use Illuminate\Support\Facades\Schema;

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

Спасибі мені допомогли
The Dead Man

24

Ця проблема викликана версією бази даних у Laravel 5.4.

Відповідно до документівIndex Lengths & MySQL / MariaDBрозділі):

Laravel використовує utf8mb4набір символів за замовчуванням, який включає підтримку зберігання "емоджи" в базі даних. Якщо ви використовуєте версію 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();

Це може бути проблемою, оскільки в електронних листах може бути до 255 символів
напр. Шалений

Ви маєте рацію @HalfCrazed, але я пропоную цю відповідь stackoverflow.com/questions/1297272
helloroy

моя проблема була точно вирішена цим рішенням. Мої поля не були електронними листами.
Tharaka Devinda

11

Якщо ви стикаєтеся з цією помилкою під час роботи над laravel під час використання команди: php artisan migrate тоді ви просто додаєте у файл два рядки: app-> Providers-> AppServiceProvider.php

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

будь ласка, перевірте це зображення . потім php artisan migrateзнову запустіть команду.


1
дуже важливо додати "використовувати схему;". Тож це найкраща відповідь
hxwtch

Ви також можете зробити це в один рядок, додавши зворотній нахил '\' перед другим рядком, як це\Schema::defaultStringLength(191);
Тахір Афріді

10

Я додаю два задухи, які працюють на мене.

1-е забруднення :

  1. Відкрити database.php файл insde конфігурації реж / папки.
  2. Редагувати 'engine' => null,в'engine' => 'InnoDB',

    Це працювало для мене.

2-е забруднення:

  1. Відкрити database.php файл insde конфігурації реж / папки.
    2. Редагувати
    'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci',
    в

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


Удачі


10

оновіть та вставіть ці рядки в програму / Провайдери / 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:

Відкрийте таблицю користувача та пароля в папці бази даних / міграцій

І просто змініть довжину електронної пошти:

$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

Замість того, щоб встановлювати обмеження по довжині, я запропонував би наступне, що працювало для мене.

Всередині:

config / database.php

замініть цей рядок на mysql:

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

з:

'engine' => null,

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. Що вам потрібно зробити, це: відредагувати додаток \ Providers.php, поставивши цей код перед декларацією класу

use Illuminate\Support\Facades\Schema;

Також додайте це до функції "завантаження" Schema::defaultStringLength(191);


2

Якщо у вас вже не призначені дані, виконайте такі дії:

  1. Перейдіть у додаток / Постачальники / AppServiceProvide.php та додайте

використовувати Illuminate \ Support \ Service \ ServiceProvider;

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

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

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

  2. виконати наступне

php artisan config: кеш

php ремісник мігрує


Це спрацювало, але додавати use Illuminate\Support\Facades\Schema; use Illuminate\Support\ServiceProvider;вже є. Сподіваюся, ви виправте це
Jimish Gamit

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

Я думаю, що примусити StringLenght до 191 року - це дуже погана ідея. Тому я розслідую, щоб зрозуміти, що відбувається.

Я помітив, що це повідомлення про помилку:

SQLSTATE [42000]: Помилка синтаксису або порушення доступу: 1071 Вказаний ключ був занадто довгим; Максимальна довжина ключа - 767 байт

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

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

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

Для Symfony 4

змінити charset: utf8mb4 на charset: utf8 в config / пакети / doctrine.yaml

Тепер мої міграційні доктрини знову працюють просто чудово.


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

спочатку видаліть усі таблиці бази даних у localhost

Змініть властивості бази даних Laravel за замовчуванням (utf8mb4) у файлі config / database.php на:

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

після цього Зміна моїх властивостей локальної бази даних utf8_unicode_ci. php ремісника мігрувати це нормально.


0

Для всіх, хто може зіткнутися з цим, моя проблема полягала в тому, що я робив колонку типу stringі намагався зробити це, ->unsigned()коли я мав на увазі, щоб це було цілим числом.


0

Підхід, що тут працює, пройшов другий парам з ключовою назвою (короткою):

$table->string('my_field_name')->unique(null,'key_name');

0

Я отримував цю помилку, хоча я вже мав її (власне тому, що я вже мав) Схема: 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 вирішило мою проблему.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.