Migração do Laravel: chave exclusiva é muito longa, mesmo se especificado

166

Estou tentando migrar uma tabela de usuários no Laravel. Quando executo minha migração, recebo este erro:

[Illuminate \ Database \ QueryException] SQLSTATE [42000]: Erro de sintaxe ou violação de acesso: 1071 A chave especificada era muito longa; o comprimento máximo da chave é 767 bytes (SQL: alter table, usersadicione users_email_uniq ( email) exclusivos )

minha migração é a seguinte:

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

Depois de pesquisar no Google, deparei-me com este relatório de erros em que Taylor diz que você pode especificar a chave de índice como o 2º parâmetro unique(), o que eu fiz. Ainda dá o erro. O que está acontecendo aqui?

harryg
fonte
Por que você está usando 320 caracteres para email? Esse pode ser o seu problema.
Antonio Carlos Ribeiro
1
Esse era realmente o problema, não fazia ideia do porquê. Mas sim, você está certo, não sei por que especifiquei o comprimento do caractere para cada campo. Os limites foram removidos
#
É engraçado como ninguém sugeriu o uso de um campo de tamanho fixo que contém o hash do email e pronto - problema resolvido para sempre, em qualquer estrutura e em qualquer banco de dados relacional. Porque é assim que garantimos a exclusividade - usando uma representação de número fixo de entrada de comprimento variável, dado o intervalo de números ser suficientemente grande (e para sha1 / sha256).
NB

Respostas:

280

Especifique um tamanho menor para o seu email:

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

Qual é o padrão, na verdade:

$table->string('email');

E você deve ser bom.

Para o Laravel 5.4, você pode encontrar uma solução neste Laravel 5.4: Erro especificado na chave especificada por muito tempo, Post do Laravel News :

Conforme descrito no guia Migrações para corrigir isso, tudo o que você precisa fazer é editar o arquivo AppServiceProvider.php e, dentro do método de inicialização, defina um tamanho de string padrão:

use Illuminate\Database\Schema\Builder;


public function boot()
{
    Builder::defaultStringLength(191);
}
Antonio Carlos Ribeiro
fonte
6
254Provavelmente, o tamanho máximo possível do e-mail vale a pena ter isso em mente, então provavelmente validaria a exclusividade usando o validator nesse caso.
Sebastian Sulinski
12
Para Laravel 5,4 , utilização \Illuminate\Database\Schema\Builder::defaultStringLength(191);para o percurso da referência função correcta
WebCoder
5
Depois de fazer a configuração no AppServiceProvider.php, esse problema ainda está acontecendo. Estou apenas confuso. Por quê? Eu reiniciei servidor, banco de dados e tudo, mas ainda assim. Por favor ajude.
precisa
3
Você deve definir o comprimento da coluna indexada de acordo com o limite de 767 bytes. Esteja ciente de que o VARCHAR pode ter 1, 2 ou 4 bytes para cada unidade de comprimento. Exemplo: utf8_mb4 (4 bytes) -> 767/4 = 191. Caso contrário, utf8_general_ci para VARCHAR (X) com X <85 (1 byte) = O (85) ou utf8_general_ci para VARCHAR (X) com X> = 86 (2 bytes) -> 767/2 = 383. Considere também outras colunas de comprimento em vários índices de coluna.
Jackie Degl'Innocenti
2
Você também pode editar diretamente o comprimento da coluna específica nos arquivos de migração, especificando um comprimento padrão para todas as colunas de sequência, pois nem todas as colunas precisarão dessa restrição, pois não estão em nenhum índice. $ table-> string ('nome_da_coluna', 191);
Jackie Degl'Innocenti
109

Atualização 1

A partir do Laravel 5.4, essas mudanças não são mais necessárias.

O Laravel 5.4 usa o conjunto de caracteres utf8mb4 por padrão, que inclui suporte para armazenar "emojis" no banco de dados. Se você estiver atualizando seu aplicativo do Laravel 5.3, não precisará mudar para esse conjunto de caracteres.

Atualização 2

As versões atuais do MariaDB de produção NÃO suportam essa configuração por padrão globalmente. É implementado no MariaDB 10.2.2+ por padrão .

Solução

E se você intencionalmente deseja usar o utf8mb4suporte a vários bytes padrão UTF8 para o padrão futuro correto (a partir do Laravel 5.4) para 😀, comece a corrigir a configuração da sua base de dados.

No Laravel config/database.phpdefina:

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

DYNAMICpermite armazenar índices de chave longos .

Configurações do servidor (por padrão, incluídas no 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

E então PARE seu servidor MySQL / MariaDB. Depois disso, comece. RESTART quente pode não funcionar.

sudo systemctl stop mysqld
sudo systemctl start mysqld

Agora você tem o Laravel 5.x com suporte a UTF8.

marcador
fonte
3
Isso pode funcionar bem o suficiente com o MySQL 5.5 (não tente reconfigurar). O 5.7 (provavelmente também 5.6) funcionou sem a necessidade de qualquer reconfiguração. O 5.7 era uma distribuição padrão do Community Server com configuração de baunilha.
Pjotr
Mudei o mecanismo no meu database.php como você mencionou, mas ele ainda está criando tabelas com row = compact, o que está causando um problema. Eu não entendi completamente, você está dizendo que não é suficiente fazer essa alteração no database.php e que também é necessário fazer as alterações no arquivo my.cnf?
precisa saber é o seguinte
É o suficiente para fazer alterações apenas no database.phparquivo de configuração e impactará o projeto local do Laravel. Verifique o deletebanco de dados antes de fazer alterações e crie-o com novas configurações. Você precisa alterar o my.cnfarquivo de configuração apenas para alterações globais no servidor (atualmente todas as novas instalações são usadas utf8mb4).
marcador
Ou - adicione outro campo, calcule o hash do email, torne o campo exclusivo, resolva o problema para sempre, evite mexer nas variáveis ​​de inicialização do banco de dados.
NB
Se alguém estiver usando a Doutrina 2 , você poderá definir ROW_FORMAT passando options={"row_format"="DYNAMIC"}para sua @Tableanotação.
Albert221
50

Se você está atualizado ou atualizado para o Laravel 5.4 Isso funcionou para mim;

Apenas 1 mudança. em AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

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

Conforme mencionado no guia de migração https://laravel.com/docs/master/migrations#creating-indexes

varta
fonte
Eu fiz isso na própria migração.
Amirmasoud 17/03/19
7
Isso ocorre (presumivelmente) porque cada caractere ocupa exatamente 4 bytes e o comprimento máximo da chave é medido em bytes, não em caracteres. Portanto, o comprimento da chave será de 191 * 4 = 764 bytes, apenas um smidgen abaixo do máximo de 767 bytes que o banco de dados suportará. As soluções precisam de explicações da IMO para que possam contribuir para o conhecimento compartilhado aqui, e não apenas fornecer "procedimentos". Mas uma solução prática, no entanto.
Jason
33

Se mais alguém se deparar com essa resposta, como eu fiz, mas por um motivo diferente, verifique o conjunto de caracteres / agrupamento do Laravel DB.

Eu estava instalando um aplicativo (Snipe-IT) e havia configurado a configuração do banco de dados do Laravel para usar o seguinte:

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

A remoção mb4das duas seqüências corrigiu o problema, embora eu acredite que a resposta de Antonio seja a verdadeira solução para o problema.

Brendan
fonte
21

Isso funcionou para mim:

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

user3278647
fonte
Isso funcionou para mim. Eu uso a versão do servidor: 10.1.22-MariaDB - distribuição de código-fonte
desenvolvedor web em Pune
16

Remova o mb4 do charset e o agrupamento de config / database.php, e ele será executado com sucesso.
'charset' => 'utf8',
'agrupamento' => 'utf8_unicode_ci',

Ramv V
fonte
15

Para laravel 5,6
Esta solução resolver o meu problema
ir para config/database.php
Encontrar o código abaixo

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

Alterar esses dois campos

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

Com isso

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

Eu enfrentei o mesmo problema e o corrigi adicionando as duas linhas abaixo no meu app / database.php

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

Meu arquivo se parece abaixo:

<?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
fonte
2
Se você instalou uma nova versão no Laravel. Por favor, remova 'mb4' de utf8mb4 & utf8mb4_unicode_ci & config / database.php
Muthu17 8/17
13

Para o laravel 5.4, basta editar o arquivo

App \ Providers \ AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

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

TO ->
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
Faizan Noor
fonte
1
Embora isso possa responder à pergunta, é melhor adicionar uma descrição de como essa resposta pode ajudar a resolver o problema. Por favor, leia Como escrevo uma boa resposta para saber mais.
Roshana Pitigala
6

eu tive o mesmo problema e estou usando um wamp

Solução: Abrir arquivo: config / database.php

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

obrigado

Purvesh
fonte
Nenhuma das respostas anteriores funcionou para mim, mas esta funcionou como um encanto! E faz todo o sentido, acredito que nas versões anteriores do mecanismo Laravel DB foi definido como InnoDB por padrão, para que não encontrássemos esses erros anteriormente.
Sasa Blagojevic
sim, precisava fazer algumas das outras respostas e isso também.
Andrew
6

No arquivo config / database.php, em que:

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

Mude esta linha para isto:

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

Para Laravel> = 5.6 usuários

Abrir AppServiceProvider.phparquivo

Use a seguinte classe

use Illuminate\Support\Facades\Schema;

Em seguida, dentro do bootmétodo, adicione a seguinte linha

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

Eu adicionei à própria migração

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

sim, eu sei que preciso considerá-lo em todas as migrações, mas eu prefiro que isso esteja escondido em algum provedor de serviços completamente independente

Manoj Thapliyal
fonte
4

Se alguém com esse problema, mesmo depois de fazer, as alterações acima mencionadas. Por exemplo, no meu caso, fiz as alterações abaixo,

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

Mas não funcionaria imediatamente por dois motivos. Uma é que se você estiver usando lúmen em vez de laravel, talvez seja necessário descomentar esta linha no seu arquivo app.php primeiro.

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

E então você deve criar o script de migração novamente com o comando artisan,

php artisan make:migration <your_table_name>

Desde agora, apenas as alterações feitas no ServiceProvider funcionarão.

dilantha111
fonte
4

para o laravel 5.7, escreva este código em appserviceprovider.php

  use Illuminate\Support\Facades\Schema;

public function boot()
{
  Schema::defaultStringLength(191);
}
ahmed farghaly
fonte
2

Altere o conjunto de caracteres para 'utf8mb4' para 'utf8' e

agrupamento para 'utf8mb4_unicode_ci' para 'utf8_unicode_ci'

no arquivo config / database.php

Funcionou para mim.

Chetan Godhani
fonte
2

O Laravel usa o utf8mb4conjunto de caracteres por padrão, que inclui suporte para armazenar "emojis" no banco de dados. Se você estiver executando uma versão do MySQL anterior à versão 5.7.7 ou MariaDB anterior à versão 10.2.2, pode ser necessário configurar manualmente o comprimento padrão da sequência gerada pelas migrações para que o MySQL crie índices para elas. Você pode configurar isso chamando o Schema::defaultStringLengthmétodo dentro de AppServiceProvider:

use Illuminate\Support\Facades\Schema;

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

Você pode conferir

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

Barakat Turki
fonte
obrigado, funciona para mim. mysql MAMP com laravel 5.6.23
bluesky
2

É porque o Laravel 5.4 usa utf8mb4, que suporta o armazenamento de emojis.

Adicione isso no seu app \ Providers \ AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

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

e você deve estar pronto para ir.

Irteza Asad
fonte
2

Se você está atualizado ou atualizado para o Laravel 5.4 e a versão mais recente, ele funciona;
Apenas uma alteração no AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

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

Eu gostaria de apontar que algo que eu perdi ...

Sou novo no Laravel e não copiei o "use Illuminate ....." porque realmente não prestei atenção, porque logo acima da inicialização da função você já tem uma declaração de uso .

Espero que ajude alguém

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

public function boot()
{
    Schema::defaultStringLength(191);
}
Samuel Aiala Ferreira
fonte
Você também pode prefixar qualquer Fachada com\
Ohgodwhy
1

Tive um problema, altere a configuração do 'config / database'

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

mantendo o mesmo padrão no banco de dados.

Então eu dei o comando

php artisan migrate
Emerson Santana Cunha
fonte
1

Em 24 de outubro de 2016, Taylor Otwell, autor do Laravel anunciado no Twitter

"utf8mb4" será o conjunto de caracteres padrão do MySQL no Laravel 5.4 para melhor suporte a emoji. Ot Mensagem do Twitter de Taylor Otwell

antes da versão 5.4, o conjunto de caracteres era utf8

Durante este século, muitos aplicativos da web incluem bate-papo ou algum tipo de plataforma para permitir que seus usuários conversem, e muitas pessoas gostam de usar emoji ou smiley. e esse é algum tipo de super personagem que exige mais espaço para armazenar e que só é possível usar utf8mb4como charset . Essa é a razão pela qual eles migram utf8mb4apenas para fins de espaço.

se você procurar na Illuminate\Database\Schema\Builderclasse, verá que $defaultStringLengthestá definido como 255 e, para modificar isso, pode prosseguir pela SchemaFachada e chamar odefaultStringLength método e passar o novo comprimento.

para executar essa alteração, chame esse método dentro de sua AppServiceProviderclasse, que está no subdiretório app \ provider 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
}

Vou sugerir o uso de 191 como o valor apenas porque o MySQL suporta 767 bytes e porque 767 / 4é o número de bytes necessários para cada caractere multibyte que você obterá.191 .

Você pode saber mais aqui Os limites do conjunto de caracteres utf8mb4 (codificação UTF-8 Unicode de 4 bytes) na contagem de colunas da tabela e no tamanho da linha

Yves Kipondo
fonte
Esta é a única resposta que explica o 191número mágico.
Illya Moskvin
1

Indo para o seu config/database.phpe altere o conjunto de caracteres e agrupamento de utf8mb4 para utf8

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

Meu problema resolvido usando esse método, boa sorte cara!

Farhan Yudhi Fatah
fonte
0

Você não terá esse problema se estiver usando o MySQL 5.7.7+ ou o MariaDB 10.2.2+.

Para atualizar o MariaDB no seu Mac usando o Brew, primeiro desvincule o atual: brew unlink mariadbe instale um dev usandobrew install mariadb --devel

Após a conclusão da instalação, pare / inicie o serviço em execução: brew services stop mariadb brew services start mariadb

A versão atual do desenvolvedor é 10.2.3. Após a conclusão da instalação, você não precisará mais se preocupar com isso e poderá usar o utf8mb4 (que agora é o padrão no Laravel 5.4) sem voltar ao utf8 nem editar o AppServiceProvider conforme proposto na documentação do Laravel: https: // laravel .com / docs / master / releases # laravel-5.4 (role para baixo até: Comprimento padrão da cadeia de migração )

Richard Dawson
fonte
0

Acabou de instalar o MariaDB 10.2.4 RC, disparou um novo projeto em branco do Laravel 5.4 e a migração padrão (colunas varchar (255)) funciona.

Não há necessidade de alterar o DB conf e o Laravael config/database.php. Assim, como o @scorer observou sobre o comportamento padrão para 10.2.2+.

kroko
fonte
0

Tudo foi bem descrito nos outros. Você pode ver mais detalhes no link abaixo (pesquise com a tecla 'Index Lengths & MySQL / MariaDB ") https://laravel.com/docs/5.5/migrations

Mas bem, não é disso que se trata esta resposta! o problema é que, ao fazer o acima, você obterá outro erro (é quando você gosta do php artisan migratecomando launch e, devido ao problema do comprimento, a operação está presa no meio. a solução é abaixo , e a tabela do usuário é criada sem o resto ou não totalmente corretamente) , precisamos rolar bac . a reversão padrão não funcionará. porque a operação de migração não gostou de terminar. você precisa excluir as novas tabelas criadas no banco de dados manualmente.

podemos fazer isso usando o funileiro, como abaixo:

L:\todos> php artisan tinker

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

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

=> null

Eu mesmo tive um problema com a tabela de usuários.

depois que você é bom de ir

php artisan migrate:rollback

php artisan migrate
Mohamed Allal
fonte
0

Defina o InnoDB do mecanismo de banco de dados:

  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
fonte
0

Se você tentou todas as outras respostas e elas não funcionaram, é possível remover todas as tabelas do banco de dados e executar o comando migrate de uma só vez usando este comando:

php artisan migrate:fresh
Tesouro
fonte