Migration Laravel: la clé unique est trop longue, même si elle est spécifiée


166

J'essaye de migrer une table d'utilisateurs dans Laravel. Lorsque j'exécute ma migration, j'obtiens cette erreur:

[Illuminate \ Database \ QueryException] SQLSTATE [42000]: Erreur de syntaxe ou violation d'accès: 1071 La clé spécifiée était trop longue; la longueur maximale de la clé est de 767 octets (SQL: alter table usersadd unique users_email_uniq ( email))

ma migration est la suivante:

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

Après quelques recherches sur Google, je suis tombé sur ce rapport de bogue où Taylor dit que vous pouvez spécifier la clé d'index comme deuxième paramètre de unique(), ce que j'ai fait. Cela donne toujours l'erreur. Qu'est-ce qui se passe ici?


Pourquoi utilisez-vous 320 caractères pour les e-mails? Cela pourrait être votre problème.
Antonio Carlos Ribeiro

1
C'était bien le problème, je ne sais pas pourquoi. Mais oui, vous avez raison, je ne sais pas pourquoi j'ai spécifié la longueur du caractère pour chaque champ. Ont supprimé ces limites
harryg

C'est drôle comme personne n'a suggéré d'utiliser un champ de longueur fixe contenant le hachage du courrier électronique et le tour est joué - problème résolu à jamais, pour n'importe quel framework et pour n'importe quelle base de données relationnelle. Parce que c'est ainsi que nous garantissons l'unicité - en utilisant une représentation à nombre fixe d'une entrée de longueur variable, étant donné que la plage de nombres est suffisamment grande (et pour sha1 / sha256 elle l'est).
NB


Réponses:


280

Spécifiez une longueur plus petite pour votre e-mail:

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

Quelle est la valeur par défaut, en fait:

$table->string('email');

Et tu devrais être bon.

Pour Laravel 5.4, vous pouvez trouver une solution dans ce Laravel 5.4: La clé spécifiée était une erreur trop longue, Laravel News post:

Comme indiqué dans le guide Migrations pour résoudre ce problème, tout ce que vous avez à faire est de modifier votre fichier AppServiceProvider.php et, dans la méthode de démarrage, définissez une longueur de chaîne par défaut:

use Illuminate\Database\Schema\Builder;


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

6
La longueur maximale possible des e-mails vaut 254donc probablement la peine de garder cela à l'esprit, donc je validerais probablement l'unicité à l'aide du validateur dans ce cas.
Sebastian Sulinski

12
Pour Laravel 5.4 , utilisez \Illuminate\Database\Schema\Builder::defaultStringLength(191);pour le chemin de référence de fonction correct
webcoder

5
Après avoir effectué la configuration dans AppServiceProvider.php, ce problème se produit toujours. Je suis juste confus. Pourquoi? J'ai redémarré le serveur, la base de données et tout, mais quand même. Veuillez aider.
Koushik Das

3
Vous devez définir la longueur de la colonne indexée en fonction de la limite de 767 octets. Sachez que VARCHAR peut avoir 1, 2 ou 4 octets pour chaque unité de longueur. Exemple: utf8_mb4 (4 octets) -> 767/4 = 191. Sinon utf8_general_ci pour VARCHAR (X) avec X <85 (1 octet) = O (85), ou utf8_general_ci pour VARCHAR (X) avec X> = 86 (2 bytes) -> 767/2 = 383. Considérez également la longueur des autres colonnes dans les index de colonnes multiples.
Jackie Degl'Innocenti

2
Vous pouvez également modifier directement la longueur de la colonne spécifique dans les fichiers de migration, en plus de spécifier une longueur par défaut pour toutes les colonnes de chaîne, car toutes les colonnes n'auront pas besoin de cette contrainte car elles ne sont dans aucun index. $ table-> string ('nom_colonne', 191);
Jackie Degl'Innocenti

109

Mise à jour 1

Depuis Laravel 5.4, ces changements ne sont plus nécessaires.

Laravel 5.4 utilise le jeu de caractères utf8mb4 par défaut, qui inclut le support du stockage des «emojis» dans la base de données. Si vous mettez à jour votre application à partir de Laravel 5.3, vous n'êtes pas obligé de basculer vers ce jeu de caractères.

Mise à jour 2

Les versions de production actuelles de MariaDB NE prennent PAS en charge ce paramètre par défaut globalement. Il est implémenté dans MariaDB 10.2.2+ par défaut .

Solution

Et si vous voulez intentionnellement utiliser le utf8mb4support multi-octets UTF8 par défaut futur correct (à partir de Laravel 5.4) pour 😀 alors commencez à corriger fix la configuration de votre base de données.

Dans Laravel config/database.phpdéfinir:

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

DYNAMICpermet de stocker de longs index clés .

Paramètres du serveur (inclus par défaut dans 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

Pour les clients:

[mysql]
default-character-set=utf8mb4

Et puis ARRÊTEZ votre serveur MySQL / MariaDB. Après cela, START. Le redémarrage à chaud peut ne pas fonctionner.

sudo systemctl stop mysqld
sudo systemctl start mysqld

Vous avez maintenant Laravel 5.x avec le support UTF8.


3
Cela pourrait assez bien fonctionner avec MySQL 5.5 (n'a pas essayé de reconfigurer). Le 5.7 (probablement aussi 5.6) fonctionnait sans aucune reconfiguration. Le 5.7 était une distribution Community Server par défaut avec une configuration vanilla.
Pjotr

J'ai changé le moteur dans ma base de données.php comme vous l'avez mentionné mais il crée toujours des tables avec row = compact ce qui pose un problème. Je n'ai pas bien compris, dites-vous qu'il ne suffit pas de faire ce changement dans database.php et qu'il est également nécessaire de faire les changements dans le fichier my.cnf?
vesperknight

Il suffit d'apporter des modifications uniquement dans le database.phpfichier de configuration et cela aura un impact sur le projet Laravel local. Assurez-vous de la deletebase de données avant d'apporter des modifications et créez-la avec de nouveaux paramètres. Vous devez modifier le my.cnffichier de configuration uniquement pour les modifications globales côté serveur (actuellement toutes les nouvelles installations utilisent utf8mb4).
buteur du

Ou - ajoutez un autre champ, calculez le hachage de l'e-mail, rendez le champ unique, résolvez le problème pour toujours, évitez de jouer avec les variables d'initialisation de la base de données.
NB

Si quelqu'un utilise Doctrine 2 , vous pouvez définir ROW_FORMAT en passant options={"row_format"="DYNAMIC"}à votre @Tableannotation.
Albert221

50

Si vous êtes sur ou mis à jour vers Laravel 5.4 Cela a fonctionné pour moi;

Juste 1 changement. dans AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

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

Comme mentionné dans le guide de migration https://laravel.com/docs/master/migrations#creating-indexes


Je l'ai fait sur la migration elle-même.
Amirmasoud

7
C'est (vraisemblablement) parce que chaque caractère occupe exactement 4 octets et que la longueur maximale de la clé est mesurée en octets et non en caractères. Ainsi, la longueur de la clé sera de 191 * 4 = 764 octets, juste un petit peu sous les 767 octets maximum que la base de données prendra en charge. Les solutions ont besoin d'explications IMO si elles doivent contribuer à la connaissance partagée ici, et pas seulement fournir des «procédures». Mais une solution pratique néanmoins.
Jason

33

Si quelqu'un d'autre tombe sur cette réponse comme je l'ai fait, mais pour une raison différente, vous pouvez vérifier votre jeu de caractères / collation Laravel DB.

J'installais une application (Snipe-IT) et j'avais configuré la configuration de la base de données Laravel pour utiliser ce qui suit:

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

La suppression mb4des deux chaînes a résolu le problème, même si je pense que la réponse d'Antonio est la vraie solution au problème.



16

Supprimez mb4 de charset et collation de config / database.php, puis il s'exécutera avec succès.
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',


15

Pour laravel 5.6
Cette solution résout mon problème,
allez à config/database.php
trouver le code ci-dessous

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

Changer ces deux champs

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

Avec ça

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

14

J'ai rencontré le même problème et je l'ai résolu en ajoutant les deux lignes ci-dessous dans mon app / database.php

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

Mon fichier ressemble à ci-dessous:

<?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
Si vous avez installé une nouvelle version dans Laravel. Veuillez supprimer 'mb4' de utf8mb4 & utf8mb4_unicode_ci & config / database.php
Muthu17

13

Pour laravel 5.4, éditez simplement le fichier

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
Bien que cela puisse répondre à la question, il est préférable d'ajouter une description de la façon dont cette réponse peut aider à résoudre le problème. Veuillez lire Comment rédiger une bonne réponse pour en savoir plus.
Roshana Pitigala

6

j'ai eu le même problème et j'utilise un wamp

Solution: ouvrez le fichier: config / database.php

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

Merci


Aucune des réponses précédentes n'a fonctionné pour moi, mais celle-ci a fonctionné à merveille! Et c'est parfaitement logique, je crois que dans les versions précédentes du moteur Laravel DB était réglé sur InnoDB par défaut, nous n'avons donc pas rencontré ces erreurs auparavant.
Sasa Blagojevic

oui, il fallait faire quelques autres réponses et ceci aussi.
Andrew

6

Dans le fichier config / database.php où:

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

Changez cette ligne en ceci:

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

5

Pour Laravel> = 5,6 utilisateurs

Ouvrir le AppServiceProvider.phpfichier

Utilisez la classe suivante

use Illuminate\Support\Facades\Schema;

Ensuite, à l'intérieur de la bootméthode, ajoutez la ligne suivante

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

4

J'ai ajouté à la migration elle-même

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

oui, je sais que je dois en tenir compte à chaque migration, mais je préférerais cela plutôt que de l'avoir caché dans un fournisseur de services totalement indépendant


4

Si quelqu'un a ce problème même après l'avoir fait, les changements mentionnés ci-dessus. Pour un exemple, dans mon cas, j'ai fait les changements ci-dessous,

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

Mais cela ne fonctionnerait pas tout de suite pour deux raisons. Premièrement, si vous utilisez lumen au lieu de laravel, vous devrez peut-être d'abord décommenter cette ligne dans votre fichier app.php.

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

Et puis vous devez créer à nouveau le script de migration avec la commande artisan,

php artisan make:migration <your_table_name>

Depuis, seules les modifications que vous avez apportées à ServiceProvider fonctionneront.


4

pour laravel 5.7, écrivez ce code dans appserviceprovider.php

  use Illuminate\Support\Facades\Schema;

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

2

Remplacez le jeu de caractères de 'utf8mb4' par 'utf8' et

classement de 'utf8mb4_unicode_ci' à 'utf8_unicode_ci'

dans le fichier config / database.php

Cela a fonctionné pour moi.


2

Laravel utilise le utf8mb4jeu de caractères par défaut, qui inclut la prise en charge du stockage des «emojis» dans la base de données. Si vous exécutez une version de MySQL antérieure à la version 5.7.7 ou MariaDB antérieure à la version 10.2.2, vous devrez peut-être configurer manuellement la longueur de chaîne par défaut générée par les migrations afin que MySQL crée des index pour eux. Vous pouvez configurer cela en appelant la Schema::defaultStringLengthméthode dans votre AppServiceProvider:

use Illuminate\Support\Facades\Schema;

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

Vous pouvez vérifier

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


merci, fonctionne pour moi. mamp mysql avec laravel 5.6.23
bluesky

2

C'est parce que Laravel 5.4 utilise utf8mb4 qui prend en charge le stockage des emojis.

Ajoutez ceci dans votre app \ Providers \ AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

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

et vous devriez être prêt à partir.


2

Si vous êtes sur ou mis à jour vers Laravel 5.4 et la dernière version, cela fonctionne;
Juste 1 changement dans AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

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

1

Je voudrais souligner que quelque chose que j'ai manqué ...

Je suis nouveau chez Laravel, et je n'ai pas copié le "use Illuminate ....." parce que je n'ai vraiment pas payé d'attention, car juste au-dessus du démarrage de la fonction, vous avez déjà une déclaration d' utilisation .

J'espère que ça aide n'importe qui

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

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

Vous pouvez également préfixer n'importe quelle façade avec\
Ohgodwhy

1

J'ai eu un problème, changez la configuration de la 'config / base de données'

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

garder le même modèle dans la base de données.

J'ai alors donné la commande

php artisan migrate

1

Le 24 octobre 2016, Taylor Otwell, l'auteur de Laravel, a été annoncé sur Twitter

"utf8mb4" sera le jeu de caractères MySQL par défaut dans Laravel 5.4 pour une meilleure prise en charge des emojis. 🙌 Message Twitter de Taylor Otwell

qui avant la version 5.4 le jeu de caractères était utf8

Au cours de ce siècle, de nombreuses applications Web incluent le chat ou une plate-forme quelconque pour permettre à leurs utilisateurs de converser, et de nombreuses personnes aiment utiliser des emoji ou des smileys. et ce sont des sortes de super caractères qui nécessitent plus d'espaces pour être stockés et qui n'est possible qu'en utilisant utf8mb4comme jeu de caractères . C'est la raison pour laquelle ils migrent utf8mb4uniquement à des fins spatiales.

si vous recherchez dans la Illuminate\Database\Schema\Builderclasse, vous verrez que le $defaultStringLengthest défini sur 255 , et pour modifier cela, vous pouvez procéder à travers la Schemafaçade et appeler la defaultStringLengthméthode et transmettre la nouvelle longueur.

pour effectuer ce changement, appelez cette méthode dans votre AppServiceProvider classe qui se trouve dans le sous-répertoire app \ fournisseurs comme ceci

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
}

Je suggérerai d'utiliser 191 comme valeur simplement parce que MySQL prend en charge 767 octets, et parce 767 / 4que c'est le nombre d'octets pris par chaque caractère multi-octets que vous obtiendrez 191.

Pour en savoir plus, cliquez ici Le jeu de caractères utf8mb4 (codage Unicode UTF-8 4 octets) sur le nombre de colonnes de table et la taille des lignes


C'est la seule réponse qui explique le 191nombre magique.
Illya Moskvin


1

Aller à votre config/database.phpet changer le jeu de caractères et la collation de utf8mb4 à utf8

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

Mon problème a été résolu en utilisant cette méthode, bonne chance mec!


0

Vous n'aurez pas ce problème si vous utilisez MySQL 5.7.7+ ou MariaDB 10.2.2+.

Pour mettre à jour MariaDB sur votre Mac en utilisant Brew, commencez par dissocier l'actuel: brew unlink mariadbpuis installez-en un de développement en utilisantbrew install mariadb --devel

Une fois l'installation terminée, arrêtez / démarrez le service en cours d'exécution: brew services stop mariadb brew services start mariadb

La version de développement actuelle est 10.2.3. Une fois l'installation terminée, vous n'aurez plus à vous en soucier et vous pouvez utiliser utf8mb4 (qui est maintenant une valeur par défaut dans Laravel 5.4) sans revenir à utf8 ni modifier AppServiceProvider comme proposé dans la documentation de Laravel: https: // laravel .com / docs / master / releases # laravel-5.4 ( faites défiler jusqu'à: Migration Default String Length )


0

Je viens d'installer MariaDB 10.2.4 RC, lancé un nouveau projet vierge Laravel 5.4 et la migration par défaut (colonnes varchar (255)) fonctionne.

Pas besoin de changer DB conf et Laravael config/database.php. Ainsi, tout comme @scorer l'a noté à propos du comportement par défaut pour 10.2.2+.


0

Tout a été bien décrit dans les autres Anwser vous pouvez voir plus de détails dans le lien ci-dessous (recherche avec la clé 'Index Lengths & MySQL / MariaDB ") https://laravel.com/docs/5.5/migrations

MAIS BIEN CE n'est pas le sujet de cette réponse! le truc, c'est que même en faisant ce qui précède, vous aimerez obtenir une autre erreur (c'est quand vous aimez lancer la php artisan migratecommande et à cause du problème de la longueur, l'opération comme coincée au milieu. la solution est ci-dessous , et la table utilisateur est comme créée sans le reste ou pas tout à fait correctement) nous devons rouler bac k. la restauration par défaut ne fonctionnera pas. car l'opération de migration n'aimait pas la finition. vous devez supprimer manuellement les nouvelles tables créées dans la base de données.

nous pouvons le faire en utilisant tinker comme ci-dessous:

L:\todos> php artisan tinker

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

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

=> null

J'ai moi-même eu un problème avec la table des utilisateurs.

après ça tu es prêt à partir

php artisan migrate:rollback

php artisan migrate

0

Définir le moteur de base de données 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

Si vous avez essayé toutes les autres réponses et qu'elles n'ont pas fonctionné, vous pouvez supprimer toutes les tables de la base de données, puis exécuter la commande migrate en une seule fois à l'aide de cette commande:

php artisan migrate:fresh
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.