Błąd migracji Laravel: Błąd składni lub naruszenie zasad dostępu: 1071 Podany klucz był za długi; maksymalna długość klucza to 767 bajtów


178

Błąd migracji w Laravel 5.4 z php artisan make:auth

[Illuminate \ Database \ QueryException] SQLSTATE [42000]: Błąd składni lub naruszenie zasad dostępu: 1071 Podany klucz był za długi; maksymalna długość klucza to 767 bajtów (SQL: alter tabl e usersadd unique users_email_unique(email ))

[Wyjątek PDO] SQLSTATE [42000]: Błąd składni lub naruszenie zasad dostępu: 1071 Podany klucz był za długi; maksymalna długość klucza to 767 bajtów


3
Powinieneś odpowiedzieć na swoje pytanie w odpowiedzi. Nie w pytaniu. stackoverflow.com/help/self-answer
Can Vural

Dzięki za sugestię @ can-vural.
absiddiqueLive

Odpowiedzi:


283

Zgodnie z oficjalną dokumentacją można to dość łatwo rozwiązać.

Dodaj następujące dwie linie kodu do 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 zawsze rezerwuje maksymalną ilość dla pola UTF8, która wynosi 4 bajty, więc z 255 + 255 z DEFAULT ZESTAWEM ZNAKÓW utf8mb4 COLLATE utf8mb4_unicode_ci; przekroczyłeś maksymalny limit długości klucza 767. Przez @scaisedge


3
Uważaj na to rozwiązanie. Jeśli na przykład indeksujesz pola wiadomości e-mail, przechowywane wiadomości e-mail mogą mieć maksymalnie 191 znaków. To mniej niż w oficjalnych stanach RFC.
shock_gone_wild


To działa i jest poprawnym rozwiązaniem, ale chciałem tylko zwrócić uwagę, że przy takim podejściu istnieją możliwe pułapki.
shock_gone_wild

Mam nadzieję, że to rozwiązanie nie ugryzie mnie w dupę w przyszłości, ale na razie to działa. Muszę jednak uważać przy indeksowaniu wiadomości e-mail.
deusofnull

4
dlaczego dokładnie 191 znaków @absiddiqueLive
PseudoAj

121

Nie wiem, dlaczego powyższe rozwiązanie i oficjalne rozwiązanie, które dodaje

Schema::defaultStringLength(191);

w AppServiceProvidernie działa dla mnie. To, co zadziałało, to edycja database.phppliku w configfolderze. Po prostu edytuj

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

do

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

i powinno działać, chociaż nie będzie można przechowywać rozszerzonych znaków wielobajtowych, takich jak emoji .

Zrobiłem to z Laravelem 5.7. Mam nadzieję, że to pomoże.


5
Użycie tego zestawu znaków pozwoli tylko na zapisanie standardowego ASCII, a nie wielobajtowych znaków specjalnych, takich jak znaki arabskie, hebrajskie, większość skryptów europejskich i oczywiście emoji. zobacz także stackoverflow.com/a/15128103/4233593
Jeff Puckett

7
Myślę, że przegapiłeś tę część use Illuminate\Support\Facades\Schema;na górze.
pimpace

@Koushik Czy z jakiej wersji Laravel korzystasz?
pimpace

Teraz jestem na 6.0. Myślę, że początkowo zrobiłem to z 5,7 lub 5,6.
Koushik Das

2
Zestawienie utf8mb4istnieje nie bez powodu, polecam go używać, jeśli możesz.
Płomień

85

Po prostu dodaję tę odpowiedź, ponieważ jest to quickestdla mnie rozwiązanie. Wystarczy ustawić domyślny silnik bazy danych do 'InnoDB'dnia

/config/database.php

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

następnie uruchom, php artisan config:cacheaby wyczyścić i odświeżyć pamięć podręczną konfiguracji


1
To powinna być oficjalna odpowiedź / rozwiązanie na to pytanie ... Dzięki
Syamsoul Azrien

1
To jest rzeczywiste rozwiązanie, inne to obejścia
Luís Cunha

3
ale jaka jest logika za tym
Zulfiqar Tariq

1
To jest właściwe rozwiązanie. Ale dlaczego nie został uwzględniony w domyślnej instalacji.
Ankit Chauhan

38

W AppServiceProvider.php, dołączasz ten kod na początku pliku.

use Illuminate\Support\Facades\Schema;

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

Dzięki pomogło mi
The Dead Man

24

Ten problem jest spowodowany w Laravel 5.4 przez wersję bazy danych.

Według dokumentów (w Index Lengths & MySQL / MariaDBdziale):

Laravel domyślnie używa utf8mb4zestawu znaków, który obejmuje obsługę przechowywania "emotikonów" w bazie danych. Jeśli używasz wersji MySQL starszej niż wersja 5.7.7 lub MariaDB starszej niż wersja 10.2.2, może być konieczne ręczne skonfigurowanie domyślnej długości łańcucha generowanego przez migracje, aby MySQL mógł utworzyć dla nich indeksy. Możesz to skonfigurować, wywołując Schema::defaultStringLengthmetodę w swoim AppServiceProvider.

Innymi słowy, w <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);
}

// ...

}

Ale jak mówi komentarz do drugiej odpowiedzi:

Uważaj na to rozwiązanie. Jeśli na przykład indeksujesz pola wiadomości e-mail, przechowywane wiadomości e-mail mogą mieć maksymalnie 191 znaków. To mniej niż w oficjalnych stanach RFC.

Tak więc dokumentacja proponuje również inne rozwiązanie:

Alternatywnie możesz włączyć tę innodb_large_prefixopcję dla swojej bazy danych. Zapoznaj się z dokumentacją bazy danych, aby uzyskać instrukcje dotyczące prawidłowego włączania tej opcji.


16

Dla kogoś, kto nie chce się zmieniać AppServiceProvider.php. (Moim zdaniem zmiana jest złym pomysłemAppServiceProvider.php tylko na potrzeby migracji )

Możesz dodać z powrotem długość danych do pliku migracji, database/migrations/jak poniżej:

create_users_table.php

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

create_password_resets_table.php

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

Może to być problem, ponieważ e-maile mogą zawierać do 255 (ish) znaków
Half Crazed

Masz rację @HalfCrazed, ale proponuję tę odpowiedź stackoverflow.com/questions/1297272
helloroy

mój problem został dokładnie rozwiązany przez to rozwiązanie. Moje pola nie były e-mailami.
Tharaka Devinda

11

Jeśli napotkasz ten błąd podczas pracy na laravel podczas używania polecenia: php artisan migrate po prostu dodaj 2 linie w pliku: app-> Providers-> AppServiceProvider.php

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

proszę sprawdzić ten obraz . następnie php artisan migrateponownie uruchom polecenie.


1
bardzo ważne jest, aby dodać „użyj schematu;”. Więc to jest najlepsza odpowiedź
hxwtch

Możesz to również zrobić w jednej linii, dodając ukośnik w tył '\' przed drugą linią w ten sposób\Schema::defaultStringLength(191);
Tahir Afridi

10

Dodaję dwa rozwiązania, które działają dla mnie.

Pierwszym rozwiązaniem jest :

  1. Otwórz plik database.php katalog konfiguracyjny insde / folder.
  2. Edytuj 'engine' => null,do'engine' => 'InnoDB',

    To zadziałało dla mnie.

Drugim rozwiązaniem jest:

  1. Otwórz plik database.php katalog konfiguracyjny insde / folder.
    2. Edytuj
    'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci',
    w

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


Powodzenia


10

zaktualizuj i wstaw te linie w 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

Rozwiązałem ten problem i zmodyfikowałem mój plik config-> database.php tak, aby polubił moją bazę danych ('charset' => 'utf8') i ('collation' => 'utf8_general_ci') , więc mój problem został rozwiązany jako podążać:

'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

Znalazłem dwa rozwiązania tego błędu

OPCJA 1:

Otwórz tabelę user i password_reset w folderze bazy danych / migracje

I po prostu zmień długość e-maila:

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

OPCJA 2:

Otwórz app/Providers/AppServiceProvider.phpplik i wewnątrz boot()metody ustaw domyślną długość ciągu:

use Illuminate\Support\Facades\Schema;

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

7

1- Idź do /config/database.phpi znajdź te linie

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

i zmień je na:

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

2- Biegnij, php artisan config:cacheaby zmienić konfigurację laravela

3- Usuń istniejące tabele w bazie danych, a następnie uruchom php artisan migrateponownie


1
to najlepsza odpowiedź dla laravel 5.8. Ale usuń już utworzone tabele
Magige Daniel

ale zgodnie z dokumentacją "utf8" będzie używać przestarzałego trybu utf8?
NoBugs

5

W pliku AppServiceProvider.php :

 use Illuminate\Support\Facades\Schema;

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

5

Zamiast ustalać limit długości, zaproponowałbym następujące rozwiązanie, które zadziałało w moim przypadku.

Wewnątrz:

config / database.php

zamień tę linię na mysql:

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

z:

'engine' => null,

4

Jak opisano w przewodniku po migracji, aby to naprawić, wszystko, co musisz zrobić, to wyedytować app/Providers/AppServiceProvider.phpplik i ustawić domyślną długość ciągu w metodzie rozruchu:

use Illuminate\Support\Facades\Schema;

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

Uwaga: najpierw musisz usunąć (jeśli masz) tabelę użytkowników, tabelę password_resets z bazy danych oraz usunąć wpisy users i password_resets z migracji tabeli .

Aby uruchomić wszystkie zaległe migracje, wykonaj migratepolecenie Artisan:

php artisan migrate

Potem wszystko powinno działać normalnie.


4

Jak już wspomniano, dodajemy do AppServiceProvider.php w App / Providers

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

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

możesz zobaczyć więcej szczegółów w linku poniżej (wyszukaj "Index Lengths & MySQL / MariaDB") https://laravel.com/docs/5.5/migrations

ALE Cóż, nie o tym wszystko opublikowałem! Chodzi o to, że nawet robiąc powyższe prawdopodobnie wystąpi kolejny błąd (to jest po uruchomieniu php artisan migratepolecenia i ze względu na problem z długością, operacja prawdopodobnie utknie w środku. rozwiązanie jest poniżej , a tabela użytkownika prawdopodobnie zostanie utworzona bez reszty lub nie do końca poprawnie) musimy wycofać się . domyślne przywracanie nie będzie działać. ponieważ operacja migracji nie lubiła zakończenia. musisz ręcznie usunąć nowo utworzone tabele w bazie danych.

możemy to zrobić za pomocą majsterkowania jak poniżej:

L:\todos> php artisan tinker

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

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

=> null

Sam miałem problem z tabelą użytkowników.

po tym jesteś gotowy

php artisan migrate:rollback

php artisan migrate


4

Rozwiązaniem, którego nikt nie mówi, jest to, że w Mysql v5.5 i późniejszych InnoDB jest domyślnym silnikiem pamięci masowej, który nie ma tego problemu, ale w wielu przypadkach, takich jak mój, istnieją stare pliki konfiguracyjne mysql ini, które używają starego silnika pamięci MYISAM , jak poniżej.

default-storage-engine=MYISAM

co stwarza wszystkie te problemy, a rozwiązaniem jest zmiana default-storage-engine na InnoDB w pliku konfiguracyjnym ini MySQL raz na zawsze, zamiast robić tymczasowe hacki.

default-storage-engine=InnoDB

A jeśli korzystasz z MySql w wersji 5.5 lub nowszej, to InnoDB jest domyślnym silnikiem, więc nie musisz go ustawiać tak jak powyżej, po prostu usuń default-storage-engine=MYISAMjeśli istnieje z inipliku i możesz zaczynać.


Dzięki! Musiałem użyć tej sugestii w połączeniu ze zmianami długości łańcucha, zestawu znaków i sortowania, aby to działało z laravel 6 i mysql 5.6. Mam nadzieję, że pomoże to innym w przyszłości.
Casper Wilkes

@CasperWilkes, nie musisz robić nic z tej długości łańcucha, kodowania znaków. Sprawdź zmienną systemową MySQL w ten sposób, show global variables like 'innodb_large_prefix';że powinna być włączona . Jeśli jest WYŁĄCZONA , możesz sprawdzić odpowiedź, jak ją włączyć. A oto więcej informacji o innodb_large_prefix na dev.mysql.com.
Ali A. Dhillon

3

Jeśli chcesz zmienić w AppServiceProvider, musisz zdefiniować długość pola e-mail w migracji. po prostu zamień pierwszą linię kodu na drugą.

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();

Po pomyślnych zmianach możesz uruchomić migrację.
Uwaga: najpierw trzeba usunąć (jeśli masz) tabeli użytkowników , password_resets tabelę z bazy danych i usuwania użytkowników i password_resets wpisów z tabeli migracji.


3

Schema::defaultStringLength(191);domyślnie zdefiniuje długość wszystkich 191 łańcuchów, co może zrujnować bazę danych. Nie możesz iść tą drogą.

Wystarczy zdefiniować długość dowolnej kolumny w klasie migracji bazy danych. Na przykład definiuję „imię”, „nazwę użytkownika” i „adres e-mail” w CreateUsersTableklasie, jak poniżej:

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
Jest to dla mnie najbardziej korzystne, ponieważ wolałbym nie modyfikować żadnych podstawowych kodów Laravel.
Okiemute Omuta

2

Jest to powszechne, ponieważ Laravel 5.4 zmienił domyślny znak bazy danych ustawiony na utf8mb4. Co musisz zrobić, to: wyedytuj plik App \ Providers.php, umieszczając ten kod przed deklaracją klasy

use Illuminate\Support\Facades\Schema;

Dodaj to również do funkcji „boot” Schema::defaultStringLength(191);


2

Jeśli nie masz już przypisanych żadnych danych do swojej bazy danych, wykonaj następujące czynności:

  1. Przejdź do app / Providers / AppServiceProvide.php i dodaj

użyj Illuminate \ Support \ ServiceProvider;

i wewnątrz metody boot ();

Schema :: defaultStringLength (191);

  1. Teraz usuń rekordy w swojej bazie danych, tabeli użytkowników np.

  2. uruchom następujące

php artisan config: cache

php artisan migrate


Zadziałało, ale trzeba dodać, use Illuminate\Support\Facades\Schema; use Illuminate\Support\ServiceProvider;że już tam jest. Mam nadzieję, że to
poprawisz

2

Jak opisano w przewodniku po migracji, aby to naprawić, wszystko, co musisz zrobić, to wyedytować plik AppServiceProvider.php i ustawić domyślną długość ciągu w metodzie rozruchu:

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

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

Mam nadzieję, że to ci pomoże ...


2

Właśnie zmodyfikowałem następujący wiersz w usersipassword_resets plik migracji.

Stary: $table->string('email')->unique();

Nowy : $table->string('email', 128)->unique();



1

Myślę, że wymuszenie StringLenght na 191 to naprawdę zły pomysł. Więc badam, aby zrozumieć, co się dzieje.

Zauważyłem, że ten komunikat o błędzie:

SQLSTATE [42000]: Błąd składni lub naruszenie zasad dostępu: 1071 Podany klucz był za długi; maksymalna długość klucza to 767 bajtów

Zaczęło się pojawiać po zaktualizowaniu mojej wersji MySQL. Więc sprawdziłem tabele za pomocą PHPMyAdmin i zauważyłem, że wszystkie nowe utworzone tabele były z sortowaniem utf8mb4_unicode_ci zamiast utf8_unicode_ci dla starych.

W moim pliku konfiguracyjnym doktryny zauważyłem, że charset został ustawiony na utf8mb4, ale wszystkie moje poprzednie tabele zostały utworzone w utf8, więc myślę, że jest to jakaś magia aktualizacji, która zaczyna działać na utf8mb4.

Teraz prostą poprawką jest zmiana zestawu znaków linii w pliku konfiguracyjnym ORM. Następnie usuń tabele za pomocą utf8mb4_unicode_ci, jeśli jesteś w trybie programisty lub napraw kodowanie, jeśli nie możesz ich upuścić.

Dla Symfony 4

zmień zestaw znaków: utf8mb4 na zestaw znaków: utf8 w config / packages / doctrine.yaml

Teraz migracje moich doktryn znów działają dobrze.


1

Zalecanym rozwiązaniem jest włączenie innodb_large_prefix opcji MySQL, dzięki czemu nie będziesz mieć kolejnych problemów. A oto jak to zrobić:

Otwórz my.iniplik konfiguracyjny MySQL i dodaj poniższe wiersze pod [mysqld]wierszem w ten sposób.

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

Następnie zapisz zmiany i uruchom ponownie usługę MySQL.

Cofnij zmiany, jeśli to konieczne, a następnie ponownie uruchom migrację.


Na wypadek, gdyby problem nadal występował, przejdź do pliku konfiguracyjnego bazy danych i ustaw

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

Mam nadzieję, że to pomoże!


1

najpierw usuń wszystkie tabele bazy danych na hoście lokalnym

Zmień właściwości domyślnej bazy danych Laravel (utf8mb4) w pliku config / database.php na:

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

później Zmiana właściwości mojej lokalnej bazy danych utf8_unicode_ci. php artisan migrate, to jest w porządku.


0

Dla każdego, kto mógłby się z tym spotkać, moim problemem było to, że tworzyłem kolumnę typu stringi próbowałem to zrobić, ->unsigned()gdy chciałem, aby była to liczba całkowita.


0

Podejście do tej pracy polegało na przekazaniu drugiego parametru z nazwą klucza (krótkiej):

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

0

Otrzymałem ten błąd, mimo że już miałem (właściwie dlatego, że już miałem) Schema :: defaultStringLength (191); w moim pliku AppServiceProvider.php.

Powodem jest to, że próbowałem ustawić wartość ciągu w jednej z moich migracji na wartość wyższą niż 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();
});

Usunięcie 1000 lub ustawienie go na 191 rozwiązało mój problem.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.