Migración laravel: la clave única es demasiado larga, incluso si se especifica

166

Estoy tratando de migrar una tabla de usuarios en Laravel. Cuando ejecuto mi migración me sale este error:

[Illuminate \ Database \ QueryException] SQLSTATE [42000]: Error de sintaxis o infracción de acceso: 1071 La clave especificada era demasiado larga; la longitud máxima de la clave es de 767 bytes (SQL: alterar tabla usersagregar usuarios únicos_email_uniq ( email))

mi migración es la siguiente:

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

Después de buscar en Google, me encontré con este informe de error donde Taylor dice que puede especificar la clave de índice como el segundo parámetro de unique(), lo que he hecho. Todavía da el error. ¿Que esta pasando aqui?

harryg
fuente
¿Por qué usas 320 caracteres para el correo electrónico? Este podría ser tu problema.
Antonio Carlos Ribeiro
1
Ese fue el problema, no tengo idea de por qué. Pero sí, tiene razón, no sé por qué especifiqué la longitud del carácter para cada campo. Han eliminado estos límites
harryg
Es curioso cómo nadie sugirió usar un campo de longitud fija que contenga hash del correo electrónico y listo, problema resuelto para siempre, para cualquier marco y para cualquier base de datos relacional. Porque así es como garantizamos la unicidad: utilizando una representación de número fijo de entrada de longitud variable, dado que el rango de números es suficientemente grande (y para sha1 / sha256 lo es).
NB
1
laravel-news.com/laravel-5-4-key-too-long-error puede obtener ayuda
matinict

Respuestas:

280

Especifique una longitud menor para su correo electrónico:

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

Cuál es el valor predeterminado, en realidad:

$table->string('email');

Y deberías ser bueno.

Para Laravel 5.4 puede encontrar una solución en este Laravel 5.4: La clave especificada fue un error demasiado largo, publicación de Laravel News :

Como se describe en la guía de Migraciones para solucionar esto, todo lo que tiene que hacer es editar su archivo AppServiceProvider.php y, dentro del método de arranque, establecer una longitud de cadena predeterminada:

use Illuminate\Database\Schema\Builder;


public function boot()
{
    Builder::defaultStringLength(191);
}
Antonio Carlos Ribeiro
fuente
66
254Probablemente valga la pena tener en cuenta la longitud máxima posible del correo electrónico , por lo que probablemente validaría la unicidad utilizando el validador en ese caso.
Sebastian Sulinski
12
Para Laravel 5.4 , use \Illuminate\Database\Schema\Builder::defaultStringLength(191);para la ruta de referencia de función correcta
webcoder
55
Después de realizar la configuración en AppServiceProvider.php, este problema aún está ocurriendo. Estoy confundido ¿Por qué? Reinicié el servidor, la base de datos y todo, pero aún así. Por favor ayuda.
Koushik Das
3
Debe establecer la longitud de la columna indexada de acuerdo con el límite de 767 bytes. Tenga en cuenta que VARCHAR puede tener 1, 2 o 4 bytes para cada unidad de longitud. Ejemplo: utf8_mb4 (4 bytes) -> 767/4 = 191. De lo contrario, utf8_general_ci para VARCHAR (X) con X <85 (1 byte) = O (85), o utf8_general_ci para VARCHAR (X) con X> = 86 (2 bytes) -> 767/2 = 383. Considere también la longitud de otras columnas en índices de columnas múltiples.
Jackie Degl'Innocenti
2
También es posible que desee editar directamente la longitud de la columna específica en los archivos de migración, especificando una longitud predeterminada para todas las columnas de cadena, ya que no todas las columnas necesitarán esta restricción ya que no están en ningún índice. $ tabla-> cadena ('nombre_columna', 191);
Jackie Degl'Innocenti
109

Actualización 1

A partir de Laravel 5.4, esos cambios ya no son necesarios.

Laravel 5.4 utiliza el conjunto de caracteres utf8mb4 de forma predeterminada, que incluye soporte para almacenar "emojis" en la base de datos. Si está actualizando su aplicación desde Laravel 5.3, no es necesario que cambie a este conjunto de caracteres.

Actualización 2

Producción actual MariaDB versiones NO admiten esta configuración de forma predeterminada a nivel mundial. Se implementa en MariaDB 10.2.2+ por defecto .

Solución

Y si intencionalmente desea utilizar el utf8mb4soporte correcto de múltiples bytes UTF8 futuro predeterminado (a partir de Laravel 5.4) para 😀, entonces comience a arreglar 😂 la configuración de su base de datos.

En Laravel config/database.phpdefine:

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

DYNAMIC permite almacenar índices de clave largos .

Configuración del servidor (por defecto incluido en 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

Para clientes:

[mysql]
default-character-set=utf8mb4

Y luego PARAR su servidor MySQL / MariaDB. Después de eso COMIENCE. El reinicio en caliente puede no funcionar.

sudo systemctl stop mysqld
sudo systemctl start mysqld

Ahora tiene Laravel 5.x con soporte UTF8.

goleador
fuente
3
Esto podría funcionar bastante bien con MySQL 5.5 (no trató de reconfigurar). El 5.7 (probablemente también 5.6) funcionó sin la necesidad de ninguna reconfiguración. El 5.7 era una distribución predeterminada del Servidor de la comunidad con configuración estándar.
Pjotr
Cambié el motor en mi database.php como mencionaste, pero todavía está creando tablas con row = compact, lo que está causando un problema. No entendí completamente, ¿estás diciendo que no es suficiente hacer este cambio en database.php y que también es necesario hacer los cambios en el archivo my.cnf?
Vesperknight
Es suficiente hacer cambios solo en el database.phparchivo de configuración e impactará en el proyecto local de Laravel. Asegúrese de deletecrear una base de datos antes de realizar cambios y crearla con una nueva configuración. my.cnfDebe cambiar el archivo de configuración solo para los cambios globales del lado del servidor (actualmente se usan todas las instalaciones nuevas utf8mb4).
anotador
O bien, agregue otro campo, calcule el hash del correo electrónico, haga que el campo sea único, resuelva el problema para siempre, evite jugar con las variables de inicialización de la base de datos.
NB
Si alguien está usando Doctrine 2 , puede configurar ROW_FORMAT pasando options={"row_format"="DYNAMIC"}a su @Tableanotación.
Albert221
50

Si está conectado o actualizado a Laravel 5.4, esto funcionó para mí;

Solo 1 cambio. en AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

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

Como se menciona en la guía de migración https://laravel.com/docs/master/migrations#creating-indexes

varta
fuente
Hice esto en la migración en sí.
Amirmasoud
77
Esto es (presumiblemente) porque cada carácter ocupa exactamente 4 bytes, y la longitud máxima de la clave se mide en bytes, no en caracteres. Entonces, la longitud de la clave será de 191 * 4 = 764 bytes, solo un smidgen por debajo del máximo de 767 bytes que admitirá la base de datos. Las soluciones necesitan explicaciones de la OMI para poder contribuir al conocimiento compartido aquí, y no solo para proporcionar "procedimientos". Pero una solución práctica, no obstante.
Jason
33

Si alguien más se topa con esta respuesta como lo hice yo, pero por una razón diferente, puede verificar su conjunto de caracteres / cotejo Laravel DB.

Estaba instalando una aplicación (Snipe-IT) y había configurado la configuración de la base de datos Laravel para usar lo siguiente:

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

La eliminación mb4de ambas cadenas solucionó el problema, aunque creo que la respuesta de Antonio es la solución real al problema.

Brendan
fuente
21

Esto funcionó para mí:

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

usuario3278647
fuente
Esto funcionó para mí. Uso la versión del servidor: 10.1.22-MariaDB - Distribución de código fuente
Desarrollador web en Pune el
16

Elimine mb4 de charset y collation de config / database.php, luego se ejecutará con éxito.
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',

Ramv V
fuente
15

Para laravel 5.6
Esta solución resuelve mi problema,
vaya a config/database.php
Buscar el código a continuación

'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 estos dos campos

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

Con este

'charset' => 'utf8',
'collation' => 'utf8_unicode_ci'
Avijit Mandal
fuente
14

Me he enfrentado al mismo problema y lo solucioné agregando las dos líneas a continuación en mi aplicación / base de datos.php

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

Mi archivo se ve a continuación:

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

    ......
Muthu17
fuente
2
Si instaló una nueva versión en Laravel. Elimine 'mb4' de utf8mb4 & utf8mb4_unicode_ci & config / database.php
Muthu17
13

Para laravel 5.4, simplemente edite el archivo

App \ Providers \ AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

public function boot()
{
    Schema::defaultStringLength(191);
}
Vanndy
fuente
7
File: config/database.php
change the following
FROM ->
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',

TO ->
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
Faizan Noor
fuente
1
Si bien esto puede responder la pregunta, es mejor agregar alguna descripción sobre cómo esta respuesta puede ayudar a resolver el problema. Lea Cómo escribo una buena respuesta para saber más.
Roshana Pitigala
6

tuve el mismo problema y estoy usando un wamp

Solución: Abra el archivo: config / database.php

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

Gracias

Purvesh
fuente
Ninguna de las respuestas anteriores funcionó para mí, ¡pero esta funcionó de maravilla! Y tiene mucho sentido, creo que en las versiones anteriores del motor Laravel DB estaba configurado en InnoDB por defecto, por lo que no encontramos estos errores anteriormente.
Sasa Blagojevic
Sí, necesitaba hacer un par de otras respuestas y esto también.
Andrew
6

En el archivo config / database.php donde:

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

Cambie esta línea a esto:

'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
Adrian
fuente
5

Para Laravel> = 5.6 usuarios

Abrir AppServiceProvider.phparchivo

Usa la siguiente clase

use Illuminate\Support\Facades\Schema;

Luego, dentro del bootmétodo, agregue la siguiente línea

public function boot()
{
    Schema::defaultStringLength(191);
}
Wael Assaf
fuente
4

Agregué a la migración en sí

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í, sé que necesito tenerlo en cuenta en cada migración, pero preferiría eso en vez de guardarlo en algún proveedor de servicios completamente ajeno.

Manoj Thapliyal
fuente
4

Si alguien tiene este problema incluso después de hacerlo, los cambios mencionados anteriormente. Por ejemplo, en mi caso hice los siguientes cambios,

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

Pero no funcionaría de inmediato por dos razones. Una es que si está utilizando lumen en lugar de laravel, es posible que primero deba descomentar esta línea en su archivo app.php.

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

Y luego tienes que crear el script de migración nuevamente con el comando artesanal,

php artisan make:migration <your_table_name>

Como ahora solo funcionarán los cambios que haya realizado en ServiceProvider.

dilantha111
fuente
4

para laravel 5.7, escriba este código en appserviceprovider.php

  use Illuminate\Support\Facades\Schema;

public function boot()
{
  Schema::defaultStringLength(191);
}
Ahmed Farghaly
fuente
2

Cambie charset de 'utf8mb4' a 'utf8' y

colación a 'utf8mb4_unicode_ci' a 'utf8_unicode_ci'

en el archivo config / database.php

Funcionó para mi.

Chetan Godhani
fuente
2

Laravel utiliza el utf8mb4conjunto de caracteres por defecto, que incluye soporte para almacenar "emojis" en la base de datos. Si está ejecutando una versión de MySQL anterior a la versión 5.7.7 o MariaDB anterior a la versión 10.2.2, es posible que deba configurar manualmente la longitud de cadena predeterminada generada por las migraciones para que MySQL cree índices para ellos. Puede configurar esto llamando al Schema::defaultStringLengthmétodo dentro de su AppServiceProvider:

use Illuminate\Support\Facades\Schema;

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

Puedes retirar de

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

Barakat Turki
fuente
gracias, funciona para mi mamp mysql con laravel 5.6.23
bluesky
2

Es porque Laravel 5.4 usa utf8mb4 que admite el almacenamiento de emojis.

Agregue esto en su aplicación \ Proveedores \ AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

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

y deberías estar listo para ir.

Irteza Asad
fuente
2

Si está conectado o actualizado a Laravel 5.4 y la última versión, funciona;
Solo 1 cambio en AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

public function boot()
{
  Schema::defaultStringLength(191);
}
Umar Tariq
fuente
1

Me gustaría señalar que algo que me perdí ...

Soy nuevo en Laravel, y no copié "use Illuminate ....." porque realmente no presté atención, porque justo encima del arranque de la función ya tienes un uso Declaración de .

Espero que ayude a cualquiera

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

public function boot()
{
    Schema::defaultStringLength(191);
}
Samuel Aiala Ferreira
fuente
También puedes prefijar cualquier Fachada con\
Ohgodwhy
1

Tuve un problema, cambie la configuración de 'config / database'

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

manteniendo el mismo patrón en la base de datos.

Entonces di la orden

php artisan migrate
Emerson Santana Cunha
fuente
1

En 24 de octubre de 2016, Taylor Otwell, el autor de Laravel, anunció en Twitter

"utf8mb4" será el conjunto de caracteres predeterminado de MySQL en Laravel 5.4 para un mejor soporte de emoji. 🙌 Publicación de Twitter de Taylor Otwell

que antes de la versión 5.4 el juego de caracteres era utf8

Durante este siglo, muchas aplicaciones web incluyen chat o alguna clase de plataforma para permitir que sus usuarios conversen, y a muchas personas les gusta usar emoji o smiley. y este es algún tipo de súper personajes que requieren más espacios para ser almacenados y que solo es posible usar utf8mb4como juego de caracteres . Esa es la razón por la que migran utf8mb4solo por motivos de espacio.

si mira hacia arriba en la Illuminate\Database\Schema\Builderclase, verá que $defaultStringLengthestá configurado en 255 , y para modificarlo, puede continuar a través de la SchemaFachada y llamar aldefaultStringLength método y pasar la nueva longitud.

para realizar ese cambio, llame a ese método dentro de su AppServiceProviderclase que se encuentra en el subdirectorio app \ proveedores como este

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
}

Sugeriré usar 191 como valor solo porque MySQL admite 767 bytes, y porque 767 / 4cuál es el número de bytes tomados por cada carácter multibyte que obtendrá191 .

Puede obtener más información aquí Los límites del conjunto de caracteres utf8mb4 (codificación Unicode UTF-8 de 4 bytes) en el recuento de columnas de tabla y el tamaño de fila

Yves Kipondo
fuente
Esta es la única respuesta que explica el 191número mágico.
Illya Moskvin
1

Ir a tu config/database.phpy cambiar el juego de caracteres y la clasificación de utf8mb4 a utf8

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

Mi problema se resolvió usando este método, ¡buena suerte amigo!

Farhan Yudhi Fatah
fuente
0

No tendrá este problema si está utilizando MySQL 5.7.7+ o MariaDB 10.2.2+.

Para actualizar MariaDB en tu Mac usando Brew, primero desvincula el actual: brew unlink mariadby luego instala un desarrollador usandobrew install mariadb --devel

Una vez realizada la instalación, detenga / inicie la ejecución del servicio: brew services stop mariadb brew services start mariadb

La versión actual del desarrollador es 10.2.3. Una vez finalizada la instalación, ya no tendrá que preocuparse por esto y puede usar utf8mb4 (que ahora es un valor predeterminado en Laravel 5.4) sin volver a utf8 ni editar AppServiceProvider como se propone en la documentación de Laravel: https: // laravel .com / docs / master / releases # laravel-5.4 (desplácese hacia abajo hasta: Longitud de cadena predeterminada de migración )

Richard Dawson
fuente
0

Acabo de instalar MariaDB 10.2.4 RC, activé un nuevo proyecto en blanco de Laravel 5.4 y funciona la migración predeterminada (columnas varchar (255)).

No es necesario cambiar DB conf y Laravael config/database.php. Así, tal como @scorer señaló sobre el comportamiento predeterminado para 10.2.2+.

kroko
fuente
0

Todo estaba bien descrito en los otros Anwser. Puede ver más detalles en el siguiente enlace (busque con la clave 'Index Lengths & MySQL / MariaDB ") https://laravel.com/docs/5.5/migrations

¡PERO BIEN, de eso no se trata esta respuesta! la cosa es que, incluso al hacer lo anterior , le gustaría obtener otro error (es decir, cuando le gusta el php artisan migratecomando de lanzamiento y debido al problema de la longitud, la operación está atascada en el medio. La solución es inferior y la tabla de usuario es como creada sin el resto o no del todo correctamente) necesitamos rodar bac . la reversión predeterminada no funcionará. porque a la operación de migración no le gustaba terminar. necesita eliminar las nuevas tablas creadas en la base de datos manualmente.

podemos hacerlo usando tinker como se muestra a continuación:

L:\todos> php artisan tinker

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

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

=> null

Yo mismo tuve un problema con la tabla de usuarios.

después de eso estás bien para ir

php artisan migrate:rollback

php artisan migrate
Mohamed Allal
fuente
0

Establecer el motor de base de datos 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();
        });
Harshad Vala
fuente
0

Si ha intentado cualquier otra respuesta y no han funcionado, puede eliminar todas las tablas de la base de datos y luego ejecutar el comando migrar de una vez usando este comando:

php artisan migrate:fresh
Tesoro
fuente