Migrazione di Laravel: la chiave univoca è troppo lunga, anche se specificata


166

Sto cercando di migrare una tabella degli utenti in Laravel. Quando eseguo la mia migrazione ottengo questo errore:

[Illuminate \ Database \ QueryException] SQLSTATE [42000]: errore di sintassi o violazione di accesso: 1071 La chiave specificata era troppo lunga; la lunghezza massima della chiave è 767 byte (SQL: modifica tabella usersaggiungi utenti_email_uniq ( email) unici

la mia migrazione è la seguente:

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

Dopo aver cercato su Google ho trovato questo bug report in cui Taylor dice che puoi specificare la chiave di indice come secondo parametro di unique(), che ho fatto. Dà ancora l'errore. Che cosa sta succedendo qui?


Perché stai usando 320 caratteri per e-mail? Questo potrebbe essere il tuo problema
Antonio Carlos Ribeiro,

1
Questo era davvero il problema, non ho idea del perché. Ma sì, hai ragione, non so perché ho specificato la lunghezza del carattere per ciascun campo. Ho rimosso questi limiti
harryg

È divertente come nessuno abbia suggerito di utilizzare un campo a lunghezza fissa che contiene l'hash dell'email e del voilà - problema risolto per sempre, per qualsiasi framework e per qualsiasi database relazionale. Perché è così che garantiamo l'unicità - usando una rappresentazione in numeri fissi di input a lunghezza variabile, dato che l'intervallo di numeri è sufficientemente ampio (e per sha1 / sha256 lo è).
NB


Risposte:


280

Specifica una lunghezza inferiore per la tua e-mail:

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

Qual è l'impostazione predefinita, in realtà:

$table->string('email');

E dovresti essere bravo.

Per Laravel 5.4 puoi trovare una soluzione in questo Laravel 5.4: la chiave specificata era un errore troppo lungo, Laravel Post:

Come indicato nella Guida alle migrazioni per risolvere questo problema, tutto ciò che devi fare è modificare il tuo file AppServiceProvider.php e all'interno del metodo di avvio impostare una lunghezza di stringa predefinita:

use Illuminate\Database\Schema\Builder;


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

6
254Probabilmente vale la pena tenere presente la massima lunghezza della posta elettronica , quindi probabilmente convaliderei l'unicità usando il validatore in quel caso.
Sebastian Sulinski,

12
Per Laravel 5.4 , utilizzare \Illuminate\Database\Schema\Builder::defaultStringLength(191);per il percorso di riferimento della funzione corretto
webcoder

5
Dopo aver effettuato la configurazione in AppServiceProvider.php, questo problema si verifica ancora. Sono solo confuso. Perché? Ho riavviato server, database e tutto ma ancora. Per favore aiuto.
Koushik Das,

3
Devi impostare la lunghezza della colonna indicizzata in base al limite di 767 byte. Tenere presente che VARCHAR può contenere 1, 2 o 4 byte per ogni unità di lunghezza. Esempio: utf8_mb4 (4 byte) -> 767/4 = 191. Altrimenti utf8_general_ci per VARCHAR (X) con X <85 (1 byte) = O (85) o utf8_general_ci per VARCHAR (X) con X> = 86 (2 byte) -> 767/2 = 383. Considera anche la lunghezza di altre colonne in più indici di colonna.
Jackie Degl'Innocenti,

2
È inoltre possibile modificare direttamente la lunghezza della colonna specifica nei file di migrazione, specificando una lunghezza predefinita per tutte le colonne di stringhe, poiché non tutte le colonne avranno bisogno di questo vincolo in quanto non sono presenti in alcun indice. $ tavola-> string ( 'column_name', 191);
Jackie Degl'Innocenti,

109

Aggiornamento 1

A partire da Laravel 5.4 tali modifiche non sono più necessarie.

Laravel 5.4 utilizza il set di caratteri utf8mb4 per impostazione predefinita, che include il supporto per la memorizzazione di "emoji" nel database. Se si aggiorna l'applicazione da Laravel 5.3, non è necessario passare a questo set di caratteri.

Aggiornamento 2

Le attuali versioni di MariaDB di produzione NON supportano questa impostazione per impostazione predefinita a livello globale. È implementato in MariaDB 10.2.2+ per impostazione predefinita .

Soluzione

E se si desidera utilizzare intenzionalmente il multi-byte UTF8 futuro-predefinito corretto (a partire da Laravel 5.4) utf8mb4 supporto supporto per 😀, iniziare a correggere 😂 la configurazione del database.

In Laravel config/database.phpdefinire:

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

DYNAMICconsente di memorizzare la chiave lunga indici .

Impostazioni del server (incluso di default in 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

Per i clienti:

[mysql]
default-character-set=utf8mb4

E poi ARRESTA il tuo server MySQL / MariaDB. Dopo quello INIZIA. Hot RESTART potrebbe non funzionare.

sudo systemctl stop mysqld
sudo systemctl start mysqld

Ora hai Laravel 5.x con supporto UTF8.


3
Questo potrebbe svegliarsi abbastanza bene con MySQL 5.5 (non ha provato a riconfigurare). Il 5.7 (probabilmente anche 5.6) ha funzionato senza la necessità di alcuna riconfigurazione. 5.7 era una distribuzione di Community Server predefinita con configurazione vanilla.
Pjotr,

Ho cambiato il motore nel mio database.php come hai detto ma sta ancora creando tabelle con row = compact che sta causando un problema. Non ho capito bene, stai dicendo che non è sufficiente apportare questa modifica in database.php e che è anche necessario apportare le modifiche nel file my.cnf?
vesperknight,

È sufficiente apportare modifiche solo nel database.phpfile di configurazione e avrà un impatto sul progetto Laravel locale. Assicurati di deletedatabase prima di apportare modifiche e crearlo con nuove impostazioni. È necessario modificare il my.cnffile di configurazione solo per le modifiche globali lato server (attualmente tutte le nuove installazioni utilizzano utf8mb4).
marcatore

Oppure - aggiungi un altro campo, calcola l'hash dell'email, rendi unico il campo, risolvi il problema per sempre, evita di armeggiare con le variabili di inizializzazione del database.
NB

Se qualcuno sta usando Doctrine 2 , puoi impostare ROW_FORMAT passando options={"row_format"="DYNAMIC"}alla tua @Tableannotazione.
Albert221,

50

Se sei su o aggiornato a Laravel 5.4 Questo ha funzionato per me;

Solo 1 cambio. in AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

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

Come menzionato nella guida alla migrazione https://laravel.com/docs/master/migrations#creating-indexes


L'ho fatto sulla migrazione stessa.
Amirmasoud,

7
Ciò è (presumibilmente) perché ogni carattere occupa esattamente 4 byte e la lunghezza massima della chiave viene misurata in byte, non in caratteri. Quindi la lunghezza della chiave sarà di 191 * 4 = 764 byte, solo uno smidgen con un massimo di 767 byte supportato dal database. Le soluzioni hanno bisogno di spiegazioni IMO se devono contribuire alla conoscenza condivisa qui e non solo fornire "procedure". Ma una soluzione pratica comunque.
Jason,

33

Se qualcun altro si imbatte in questa risposta come ho fatto io, ma per un motivo diverso, è possibile controllare il set di caratteri / le regole di confronto di Laravel DB.

Stavo installando un'applicazione (Snipe-IT) e avevo configurato la configurazione del database Laravel per utilizzare quanto segue:

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

La rimozione mb4da entrambe le stringhe ha risolto il problema, anche se credo che la risposta di Antonio sia la vera soluzione al problema.


21

Questo ha funzionato per me:

 $table->charset = 'utf8';
 $table->collation = 'utf8_unicode_ci';


Questo ha funzionato per me. Uso la versione Server: 10.1.22-MariaDB - Distribuzione sorgente
Web Developer a Pune il

16

Rimuovi mb4 da charset e fascicolazione da config / database.php, quindi verrà eseguito correttamente.
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',


15

Per laravel 5.6
Questa soluzione risolve il mio problema
vai a config/database.php
Trova il codice qui sotto

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

Cambia questi due campi

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

Con questo

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

14

Ho riscontrato lo stesso problema e l'ho risolto aggiungendo le due righe seguenti nella mia app / database.php

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

Il mio file è simile al seguente:

<?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
Se hai installato una nuova versione in Laravel. Rimuovi 'mb4' da utf8mb4 & utf8mb4_unicode_ci & config / database.php
Muthu17

13

Per laravel 5.4, modifica semplicemente il file

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
Mentre questo può rispondere alla domanda, è meglio aggiungere una descrizione di come questa risposta possa aiutare a risolvere il problema. Si prega di leggere Come posso scrivere una buona risposta per saperne di più.
Roshana Pitigala,

6

ho avuto lo stesso problema e sto usando un wamp

Soluzione: aprire il file: config / database.php

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

Grazie


Nessuna delle risposte precedenti ha funzionato per me, ma questa ha funzionato come un fascino! Ed ha perfettamente senso, credo che nelle versioni precedenti del motore Laravel DB fosse impostato su InnoDB per impostazione predefinita, quindi non abbiamo riscontrato questi errori in precedenza.
Sasa Blagojevic,

sì, ho bisogno di fare un paio di altre risposte e anche questo.
Andrew,

6

Nel file config / database.php dove:

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

Cambia questa riga in questo:

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

5

Per Laravel> = 5.6 utenti

Apri il AppServiceProvider.phpfile

Usa la seguente classe

use Illuminate\Support\Facades\Schema;

Quindi all'interno del bootmetodo aggiungere la seguente riga

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

4

Ho aggiunto alla migrazione stessa

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

sì, lo so che devo considerarlo su ogni migrazione, ma preferirei che lo nascondessi in un fornitore di servizi completamente indipendente


4

Se qualcuno ha questo problema anche dopo averlo fatto, le modifiche sopra menzionate. Ad esempio, nel mio caso ho apportato le modifiche seguenti,

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

Ma non avrebbe funzionato subito per due motivi. Uno è se stai usando lumen invece di laravel, potresti dover prima decommentare questa riga nel tuo file app.php.

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

E poi devi creare di nuovo lo script di migrazione con il comando artigianale,

php artisan make:migration <your_table_name>

Da ora funzioneranno solo le modifiche apportate a ServiceProvider.


4

per laravel 5.7 scrivere questo codice in appserviceprovider.php

  use Illuminate\Support\Facades\Schema;

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

2

Cambia charset da "utf8mb4" a "utf8" e

regole di confronto in "utf8mb4_unicode_ci" in "utf8_unicode_ci"

nel file config / database.php

Ha funzionato per me.


2

Laravel utilizza il utf8mb4set di caratteri per impostazione predefinita, che include il supporto per la memorizzazione di "emoji" nel database. Se si esegue una versione di MySQL precedente alla versione 5.7.7 o MariaDB precedente alla versione 10.2.2, potrebbe essere necessario configurare manualmente la lunghezza della stringa predefinita generata dalle migrazioni per consentire a MySQL di creare indici per esse. Puoi configurarlo chiamando il Schema::defaultStringLengthmetodo nel tuo AppServiceProvider:

use Illuminate\Support\Facades\Schema;

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

Puoi fare il check out di

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


grazie, funziona per me. mamp mysql con laravel 5.6.23
bluesky

2

È perché Laravel 5.4 utilizza utf8mb4 che supporta la memorizzazione di emoji.

Aggiungi questo nella tua app \ Providers \ AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

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

e dovresti essere bravo ad andare.


2

Se sei su o aggiornato a Laravel 5.4 e all'ultima versione funziona;
Solo 1 modifica in AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

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

1

Vorrei sottolineare qualcosa che mi mancava ...

Sono nuovo in Laravel e non ho copiato "usa Illuminate ....." perché non ho prestato attenzione, perché proprio sopra la funzione di avvio hai sempre una Dichiarazione d' uso .

Spero che aiuti chiunque

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

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

Puoi anche \
aggiungere

1

Ho avuto un problema, cambiare la configurazione di 'config / database'

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

mantenendo lo stesso modello nel database.

Ho quindi dato il comando

php artisan migrate

1

Nel 24 ottobre 2016 Taylor Otwell, l'autore di Laravel annunciato su Twitter, è Twitter

"utf8mb4" sarà il set di caratteri MySQL predefinito in Laravel 5.4 per un migliore supporto emoji. 🙌 Post di Twitter di Taylor Otwell

che prima della versione 5.4 era il set di caratteri utf8

Durante questo secolo molte app web includono chat o qualche tipo di piattaforma per consentire ai loro utenti di conversare e molte persone amano usare le emoji o le emoticon. e questo è una sorta di super personaggi che richiedono più spazi per essere memorizzati e che è possibile utilizzare solo utf8mb4come set di caratteri . Questo è il motivo per cui migrano utf8mb4solo per scopi spaziali.

se cerchi nella Illuminate\Database\Schema\Builderclasse vedrai che $defaultStringLengthè impostato su 255 e per modificarlo puoi procedere attraverso la Schemafacciata e chiamare ildefaultStringLength metodo e passare la nuova lunghezza.

per eseguire tale modifica chiama quel metodo all'interno della tua AppServiceProviderclasse che si trova nella sottodirectory app \ provider in questo modo

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
}

Suggerirò di usare 191 come valore solo perché MySQL supporta 767 byte e perché 767 / 4è il numero di byte che assume ogni carattere multibyte 191.

Puoi saperne di più qui Il set di caratteri utf8mb4 (codifica Unicode UTF-8 a 4 byte) Limiti sul conteggio delle colonne della tabella e sulla dimensione della riga


Questa è l'unica risposta che spiega il 191numero magico.
Illya Moskvin,


1

Andare da te config/database.phpe cambiare il set di caratteri e le regole di confronto da utf8mb4 a utf8

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

Il mio problema è stato risolto usando questo metodo, buona fortuna amico!


0

Non avrai questo problema se stai usando MySQL 5.7.7+ o MariaDB 10.2.2+.

Per aggiornare MariaDB sul tuo Mac usando Brew scollega prima quello corrente: brew unlink mariadbe poi installa uno dev usandobrew install mariadb --devel

Al termine dell'installazione, arrestare / avviare il servizio in esecuzione: brew services stop mariadb brew services start mariadb

L'attuale versione di sviluppo è 10.2.3. Al termine dell'installazione non dovrai più preoccuparti di questo e puoi usare utf8mb4 (che ora è un valore predefinito in Laravel 5.4) senza tornare a utf8 né modificare AppServiceProvider come proposto nella documentazione di Laravel: https: // laravel .com / docs / master / release # laravel-5.4 (scorrere fino a: Migration Default String Length )


0

Appena installato MariaDB 10.2.4 RC, avviato un nuovo progetto Laravel 5.4 vuoto e funziona la migrazione predefinita (colonne varchar (255)).

Non è necessario modificare DB conf e Laravael config/database.php. Così, come notato da @scorer sul comportamento predefinito per 10.2.2+.


0

Tutto è stato ben descritto nelle altre Anwser, puoi vedere maggiori dettagli nel link qui sotto (cerca con il tasto 'Index Lengths & MySQL / MariaDB ") https://laravel.com/docs/5.5/migrations

MA BENE NON è questa la risposta! il fatto è che anche facendo quanto sopra ti piacerebbe ottenere un altro errore (è quando ti piace il php artisan migratecomando di avvio ea causa del problema della lunghezza, l'operazione come bloccata nel mezzo. La soluzione è sotto , e la tabella utente è come creata senza il resto o non del tutto correttamente) dobbiamo rotolare il bac k. il rollback predefinito non funzionerà. perché l'operazione di migrazione non ha gradito il completamento. è necessario eliminare manualmente le nuove tabelle create nel database.

possiamo farlo usando armeggiare come sotto:

L:\todos> php artisan tinker

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

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

=> null

Io stesso ho avuto un problema con la tabella degli utenti.

dopo che il tuo bene per andare

php artisan migrate:rollback

php artisan migrate

0

Impostare il motore di database 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

Se hai provato ogni altra risposta e non hanno funzionato, puoi eliminare tutte le tabelle dal database e quindi eseguire il comando migrate in una sola volta usando questo comando:

php artisan migrate:fresh
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.