Laravel-Migration: Der eindeutige Schlüssel ist zu lang, auch wenn er angegeben ist


163

Ich versuche, eine Benutzertabelle in Laravel zu migrieren. Wenn ich meine Migration ausführe, wird folgende Fehlermeldung angezeigt:

[Illuminate \ Database \ QueryException] SQLSTATE [42000]: Syntaxfehler oder Zugriffsverletzung: 1071 Der angegebene Schlüssel war zu lang. Die maximale Schlüssellänge beträgt 767 Byte (SQL: alter table usersadd unique users_email_uniq ( email))

Meine Migration ist wie folgt:

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');
});

Nach einigem googeln bin ich auf diesen Fehlerbericht gestoßen, in dem Taylor sagt, dass Sie den Indexschlüssel als zweiten Parameter angeben können unique(), was ich getan habe. Es gibt immer noch den Fehler. Was geht hier vor sich?


Warum verwenden Sie 320 Zeichen für E-Mails? Dies könnte Ihr Problem sein.
Antonio Carlos Ribeiro

1
Das war in der Tat das Problem, keine Ahnung warum. Aber ja, Sie haben Recht, ich weiß nicht, warum ich die Zeichenlänge für jedes Feld angegeben habe. Habe diese Grenzen
aufgehoben

Es ist lustig, wie niemand vorgeschlagen hat, ein Feld mit fester Länge zu verwenden, das den Hash der E-Mail und des Voila enthält - ein Problem, das für immer gelöst ist, für jedes Framework und für jede relationale Datenbank. Denn auf diese Weise garantieren wir die Eindeutigkeit - unter Verwendung einer Darstellung mit fester Zahl für Eingaben variabler Länge, da der Zahlenbereich ausreichend groß ist (und für sha1 / sha256 auch).
NB


Antworten:


278

Geben Sie eine kleinere Länge für Ihre E-Mail an:

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

Welches ist eigentlich die Standardeinstellung:

$table->string('email');

Und du solltest gut sein.

Für Laravel 5.4 finden Sie eine Lösung in diesem Laravel 5.4: Angegebener Schlüssel war zu lang Fehler, Laravel News post:

Wie im Migrationshandbuch beschrieben, müssen Sie lediglich Ihre AppServiceProvider.php-Datei bearbeiten und innerhalb der Startmethode eine Standardzeichenfolgenlänge festlegen:

use Illuminate\Database\Schema\Builder;


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

6
Die maximal mögliche E-Mail-Länge ist 254es wahrscheinlich wert, dies zu berücksichtigen. Daher würde ich die Eindeutigkeit in diesem Fall wahrscheinlich mit dem Validator überprüfen.
Sebastian Sulinski

12
Für Laravel 5.4 , Verwendung \Illuminate\Database\Schema\Builder::defaultStringLength(191);für Pfade korrekt Funktionsreferenz
WebCoder

5
Nach der Konfiguration in der Datei AppServiceProvider.php tritt dieses Problem weiterhin auf. Ich bin nur verwirrt. Warum? Ich habe Server, Datenbank und alles aber immer noch neu gestartet. Bitte helfen Sie.
Koushik Das

3
Sie müssen die Länge der indizierten Spalte entsprechend dem Limit von 767 Byte festlegen. Beachten Sie, dass VARCHAR für jede Längeneinheit 1, 2 oder 4 Byte haben kann. Beispiel: utf8_mb4 (4 Bytes) -> 767/4 = 191. Andernfalls utf8_general_ci für VARCHAR (X) mit X <85 (1 Byte) = O (85) oder utf8_general_ci für VARCHAR (X) mit X> = 86 (2) Bytes) -> 767/2 = 383. Berücksichtigen Sie auch andere Spaltenlängen in mehreren Spaltenindizes.
Jackie Degl'Innocenti

2
Möglicherweise möchten Sie auch die Länge der bestimmten Spalte in den Migrationsdateien direkt bearbeiten, indem Sie eine Standardlänge für alle Zeichenfolgenspalten angeben, da nicht alle Spalten diese Einschränkung benötigen, da sie in keinem Index enthalten sind. $ table-> string ('Spaltenname', 191);
Jackie Degl'Innocenti

109

Update 1

Ab Laravel 5.4 sind diese Änderungen nicht mehr erforderlich.

Laravel 5.4 verwendet standardmäßig den Zeichensatz utf8mb4, der die Speicherung von "Emojis" in der Datenbank unterstützt. Wenn Sie Ihre Anwendung von Laravel 5.3 aktualisieren, müssen Sie nicht zu diesem Zeichensatz wechseln.

Update 2

Aktuelle MariaDB-Produktionsversionen unterstützen diese Einstellung standardmäßig NICHT global. Es ist standardmäßig in MariaDB 10.2.2+ implementiert .

Lösung

Und wenn Sie absichtlich die richtige UTF8- utf8mb4Multibyte - Unterstützung für 😀 verwenden möchten (ab Laravel 5.4), beginnen Sie mit der Korrektur Ihrer Datenbankkonfiguration.

In Laravel config/database.phpdefinieren Sie:

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

DYNAMICErmöglicht das Speichern langer Schlüsselindizes .

Servereinstellungen (standardmäßig in MySQL 5.7.7+ / MariaDB 10.2.2+ enthalten):

[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

Für Kunden:

[mysql]
default-character-set=utf8mb4

Und dann STOPPEN Sie Ihren MySQL / MariaDB-Server. Nach diesem START. Hot RESTART funktioniert möglicherweise nicht.

sudo systemctl stop mysqld
sudo systemctl start mysqld

Jetzt haben Sie Laravel 5.x mit UTF8-Unterstützung.


3
Dies könnte mit MySQL 5.5 gut genug funktionieren (ich habe nicht versucht, es neu zu konfigurieren). Die Version 5.7 (wahrscheinlich auch 5.6) funktionierte ohne Neukonfiguration. 5.7 war eine Standard-Community Server-Distribution mit Vanille-Konfiguration.
Pjotr

Ich habe die Engine in meiner database.php geändert, wie Sie bereits erwähnt haben, aber es werden immer noch Tabellen mit row = compact erstellt, was ein Problem verursacht. Ich habe nicht ganz verstanden, sagen Sie, dass es nicht ausreicht, diese Änderung in database.php vorzunehmen, und dass es auch erforderlich ist, die Änderungen in der Datei my.cnf vorzunehmen?
Vesperknight

Es reicht aus, Änderungen nur in der database.phpKonfigurationsdatei vorzunehmen, und dies wirkt sich auf das lokale Laravel-Projekt aus. Stellen Sie sicher, dass Sie eine deleteDatenbank erstellen, bevor Sie Änderungen vornehmen, und erstellen Sie sie mit neuen Einstellungen. Sie müssen die my.cnfKonfigurationsdatei nur für globale serverseitige Änderungen ändern (derzeit werden alle Neuinstallationen verwendet utf8mb4).
Torschütze

Oder - fügen Sie ein weiteres Feld hinzu, berechnen Sie den Hash der E-Mail, machen Sie das Feld eindeutig, lösen Sie das Problem für immer und vermeiden Sie es, mit Datenbankinitialisierungsvariablen herumzuspielen.
NB

Wenn jemand Doctrine 2 verwendet , können Sie ROW_FORMAT festlegen, indem Sie options={"row_format"="DYNAMIC"}an Ihre @TableAnmerkung übergeben.
Albert221

50

Wenn Sie auf Laravel 5.4 sind oder auf Laravel 5.4 aktualisiert haben, hat dies bei mir funktioniert.

Nur 1 Änderung. in AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

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

Wie im Migrationshandbuch https://laravel.com/docs/master/migrations#creating-indexes erwähnt


Ich habe dies bei der Migration selbst getan.
Amirmasoud

7
Dies liegt (vermutlich) daran, dass jedes Zeichen genau 4 Bytes belegt und die maximale Schlüssellänge in Bytes und nicht in Zeichen gemessen wird. Die Schlüssellänge beträgt also 191 * 4 = 764 Bytes, nur ein Smidgen unter den maximal 767 Bytes, die die Datenbank unterstützt. Lösungen benötigen IMO-Erklärungen, wenn sie zum hier geteilten Wissen beitragen und nicht nur "Verfahren" bereitstellen sollen. Aber trotzdem eine praktische Lösung.
Jason

33

Wenn jemand wie ich auf diese Antwort stößt, aber aus einem anderen Grund, können Sie Ihren Laravel DB-Zeichensatz / Ihre Laravel DB-Sortierung überprüfen.

Ich habe eine Anwendung (Snipe-IT) installiert und die Laravel-Datenbankkonfiguration so konfiguriert, dass Folgendes verwendet wird:

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

Das Entfernen mb4von beiden Zeichenfolgen hat das Problem behoben, obwohl ich glaube, dass Antonios Antwort die wirkliche Lösung für das Problem ist.



16

Entfernen Sie mb4 aus dem Zeichensatz und die Sortierung aus config / database.php. Anschließend wird es erfolgreich ausgeführt.
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',


15

Für Laravel 5.6
Diese Lösung löst mein Problem.
Gehen Sie zu config/database.php
Finden Sie den Code unten

'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,
],

Ändern Sie diese beiden Felder

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

Mit diesem

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

14

Ich habe das gleiche Problem festgestellt und es behoben, indem ich die folgenden zwei Zeilen in meine app / database.php eingefügt habe

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

Meine Datei sieht wie folgt aus:

<?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
Wenn Sie eine neue Version in Laravel installiert haben. Bitte entfernen Sie 'mb4' aus utf8mb4 & utf8mb4_unicode_ci & config / database.php
Muthu17

13

Für Laravel 5.4 bearbeiten Sie einfach die Datei

App \ Providers \ 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
Während dies die Frage beantworten kann, ist es besser, eine Beschreibung hinzuzufügen, wie diese Antwort zur Lösung des Problems beitragen kann. Bitte lesen Sie Wie schreibe ich eine gute Antwort , um mehr zu erfahren ?
Roshana Pitigala

6

Ich hatte das gleiche Problem und ich benutze einen Wamp

Lösung: Öffnen Sie die Datei: config / database.php

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

Vielen Dank


Keine der vorherigen Antworten hat bei mir funktioniert, aber diese hat wie ein Zauber funktioniert! Und es macht durchaus Sinn, ich glaube, dass in früheren Versionen der Laravel DB-Engine standardmäßig InnoDB eingestellt war, sodass diese Fehler zuvor nicht aufgetreten sind.
Sasa Blagojevic

Ja, ich musste ein paar andere Antworten machen und das auch.
Andrew

6

In der Datei config / database.php wo:

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

Ändern Sie diese Zeile in folgende:

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

4

Ich habe die Migration selbst hinzugefügt

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

Ja, ich weiß, dass ich es bei jeder Migration berücksichtigen muss, aber ich würde es lieber tun, als es in einem völlig unabhängigen Dienstanbieter zu verstecken


4

Wenn jemand dieses Problem auch danach hat, ändern sich die oben genannten. Zum Beispiel habe ich in meinem Fall die folgenden Änderungen vorgenommen:

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

Aber es würde aus zwei Gründen nicht sofort funktionieren. Wenn Sie Lumen anstelle von Laravel verwenden, müssen Sie diese Zeile möglicherweise zuerst in Ihrer app.php-Datei auskommentieren.

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

Und dann müssen Sie das Migrationsskript erneut mit dem Befehl artisan erstellen.

php artisan make:migration <your_table_name>

Seitdem funktionieren nur die Änderungen, die Sie an ServiceProvider vorgenommen haben.


4

Für Laravel> = 5.6 Benutzer

AppServiceProvider.phpDatei öffnen

Verwenden Sie die folgende Klasse

use Illuminate\Support\Facades\Schema;

Fügen Sie dann innerhalb der bootMethode die folgende Zeile hinzu

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

3

Für Laravel 5.7 schreiben Sie diesen Code in appserviceprovider.php

  use Illuminate\Support\Facades\Schema;

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

2

Ändern Sie den Zeichensatz von 'utf8mb4' in 'utf8' und

Sortierung zu 'utf8mb4_unicode_ci' zu 'utf8_unicode_ci'

in der Datei config / database.php

Es hat bei mir funktioniert.


2

Laravel verwendet utf8mb4standardmäßig den Zeichensatz, der die Speicherung von "Emojis" in der Datenbank unterstützt. Wenn Sie eine Version von MySQL ausführen, die älter als die Version 5.7.7 oder MariaDB älter als die Version 10.2.2 ist, müssen Sie möglicherweise die durch Migrationen generierte Standardzeichenfolgenlänge manuell konfigurieren, damit MySQL Indizes für sie erstellt. Sie können dies konfigurieren, indem Sie die Schema::defaultStringLengthMethode in Ihrem Verzeichnis aufrufen AppServiceProvider:

use Illuminate\Support\Facades\Schema;

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

Sie können auschecken

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


Danke, arbeitet für mich. Mamp Mysql mit Laravel 5.6.23
Bluesky

2

Es ist , weil Laravel 5.4 Anwendungen utf8mb4 , die Stützen Emojis zu speichern.

Fügen Sie dies in Ihre app \ Providers \ AppServiceProvider.php ein

use Illuminate\Support\Facades\Schema;

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

und du solltest gut sein zu gehen.


2

Wenn Sie Laravel 5.4 und die neueste Version verwenden oder auf diese aktualisieren, funktioniert dies.
Nur 1 Änderung in AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

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

1

Ich möchte darauf hinweisen, dass ich etwas verpasst habe ...

Ich bin neu bei Laravel und habe das "use Illuminate ....." nicht kopiert, weil ich wirklich nicht darauf geachtet habe, weil direkt über dem Funktionsstart, den Sie bereits haben, eine use- Anweisung vorhanden ist.

Hoffe das hilft jedem

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

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

Sie können auch einfach jede Fassade mit\
Ohgodwhy

1

Ich hatte ein Problem, ändere die Konfiguration der 'config / database'

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

Beibehaltung des gleichen Musters in der Datenbank.

Ich gab dann den Befehl

php artisan migrate

1

Am 24. Oktober 2016 gab Taylor Otwell, der Autor von Laravel, auf Twitter bekannt

"utf8mb4" ist der Standard-MySQL-Zeichensatz in Laravel 5.4 für eine bessere Emoji-Unterstützung. 🙌 Taylor Otwell Twitter Beitrag

was vor Version 5.4 der Zeichensatz war utf8

Während dieses Jahrhunderts enthalten viele Web-Apps Chat oder eine Plattform, auf der sich Benutzer unterhalten können, und viele Menschen verwenden gerne Emoji oder Smiley. und dies sind Superzeichen, für deren Speicherung mehr Leerzeichen erforderlich sind und die nur utf8mb4als Zeichensatz verwendet werden können . Das ist der Grund, warum sie migrierenutf8mb4 nur für Weltraumzwecke .

Wenn Sie in der Illuminate\Database\Schema\BuilderKlasse nachschlagen, werden Sie feststellen, dass der Wert $defaultStringLengthauf 255 eingestellt ist. Um dies zu ändern, können Sie über die SchemaFassade vorgehen und den aufrufendefaultStringLength Methode und die neue Länge übergeben.

Um diese Änderung durchzuführen, rufen Sie diese Methode in Ihrer AppServiceProviderKlasse auf, die sich wie folgt im Unterverzeichnis app \ provider befindet

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
}

Ich werde vorschlagen, 191 als Wert zu verwenden, nur weil MySQL 767 Bytes unterstützt und weil 767 / 4dies die Anzahl der Bytes ist, die jedes Multibyte-Zeichen benötigt191 .

Weitere Informationen finden Sie hier. Der utf8mb4-Zeichensatz (4-Byte-UTF-8-Unicode-Codierung) begrenzt die Anzahl der Tabellenspalten und die Zeilengröße


Dies ist die einzige Antwort, die die 191magische Zahl erklärt .
Illya Moskvin

1

LÖSUNG:

Ändern Sie zuerst die defaultStringLength in der Datei app \ Providers \ AppServiceProvider.php in 191 :

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

Ändern Sie dann die Werte für Zeichensatz und Sortierung in config \ database.php wie folgt :

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

( Link zum MariaDB-Zeichensatz )


1

Gehen Sie zu Ihrem config/database.phpund ändern Sie den Zeichensatz und die Sortierung von utf8mb4 in utf8

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

Mein Problem wurde mit dieser Methode gelöst, viel Glück, Alter!


0

Dieses Problem tritt nicht auf, wenn Sie MySQL 5.7.7+ oder MariaDB 10.2.2+ verwenden.

Um MariaDB auf Ihrem Mac mit Brew zu aktualisieren, entfernen Sie zuerst die Verknüpfung der aktuellen brew unlink mariadbund installieren Sie dann eine Entwickler-Version mitbrew install mariadb --devel

Nach Abschluss der Installation stoppen / starten Sie den laufenden Dienst: brew services stop mariadb brew services start mariadb

Die aktuelle Entwicklungsversion ist 10.2.3. Nach Abschluss der Installation müssen Sie sich darüber keine Gedanken mehr machen und können utf8mb4 (das ist jetzt eine Standardeinstellung in Laravel 5.4) verwenden, ohne wieder zu utf8 zu wechseln oder AppServiceProvider zu bearbeiten, wie in der Laravel-Dokumentation vorgeschlagen: https: // laravel .com / docs / master / release # laravel-5.4 (scrollen Sie nach unten zu: Migration Standard String String Length )


0

Gerade MariaDB 10.2.4 RC installiert, neues leeres Laravel 5.4-Projekt gestartet und die Standardmigration (varchar (255) Spalten) funktioniert.

DB conf und Laravael müssen nicht geändert werden config/database.php. So wie @scorer das Standardverhalten für 10.2.2+ notiert hat.


0

Alles wurde in den anderen Anwser gut beschrieben. Weitere Details finden Sie im folgenden Link (Suche mit dem Schlüssel 'Indexlängen & MySQL / MariaDB ") https://laravel.com/docs/5.5/migrations

ABER GUT, darum geht es in dieser Antwort nicht! Die Sache ist, auch wenn Sie die oben genannten Schrittephp artisan migrate ausführen, möchten Sie einen weiteren Fehler erhalten (wenn Sie den Startbefehl mögen und aufgrund des Problems der Länge die Operation wie in der Mitte stecken bleibt. Die Lösung ist unten und die Benutzertabelle ist wie ohne erstellt den Rest oder nicht ganz richtig) müssen wir bac rollen . Das Standard-Rollback reicht nicht aus. weil der Vorgang der Migration nicht gerne beendet wurde. Sie müssen die neu erstellten Tabellen in der Datenbank manuell löschen.

wir können es mit basteln wie unten machen:

L:\todos> php artisan tinker

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

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

=> null

Ich selbst hatte ein Problem mit der Benutzertabelle.

danach ist es gut zu gehen

php artisan migrate:rollback

php artisan migrate

0

Datenbank-Engine einstellen 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

Wenn Sie jede andere Antwort ausprobiert haben und sie nicht funktioniert hat, können Sie alle Tabellen aus der Datenbank löschen und dann den Befehl migrate auf einmal mit diesem Befehl ausführen:

php artisan migrate:fresh
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.