Erro de migração do Laravel: erro de sintaxe ou violação de acesso: 1071 A chave especificada era muito longa; o comprimento máximo da chave é 767 bytes

177

Erro de migração no Laravel 5.4 com php artisan make:auth

[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: alterar tabela e usersadicionar exclusivo users_email_unique( email))

[PDOException] 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

absiddiqueLive
fonte
3
Você deve responder sua pergunta em uma resposta. Não está em questão. stackoverflow.com/help/self-answer
Pode Vural 15/17
Obrigado pela sugestão @ can-vural, eu fiz.
absiddiqueLive

Respostas:

283

De acordo com a documentação oficial , você pode resolver isso facilmente.

Adicione as duas linhas de código a seguir no AppServiceProvider.php (/app/Providers/AppServiceProvider.php)

use Illuminate\Database\Schema\Builder; // Import Builder where defaultStringLength method is defined

function boot()
{
    Builder::defaultStringLength(191); // Update defaultStringLength
}

O MySQL reserva sempre a quantidade máxima para um campo UTF8 de 4 bytes, com 255 + 255 com seu DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; você está acima do limite máximo de comprimento da chave 767. Por @scaisedge

absiddiqueLive
fonte
3
Tenha cuidado com esta solução. Se você indexar campos de email, por exemplo, os emails armazenados podem ter apenas um comprimento máximo de 191 caracteres. Isso é menor do que os estados oficiais da RFC.
Shock_gone_wild
Está funcionando e é uma solução válida, mas eu só queria ressaltar que existem possíveis armadilhas usando essa abordagem.
Shock_gone_wild 17/02
Espero que essa solução não venha me morder no futuro, mas, por enquanto, isso funciona. No entanto, terei que ter cuidado com a indexação de e-mails.
Deusofnull
4
por que exatamente 191 caracteres @absiddiqueLive
PseudoAj
121

Não sei por que a solução acima e a solução oficial que está adicionando

Schema::defaultStringLength(191);

em AppServiceProvidernão funcionou para mim. O que funcionou foi a edição do database.phparquivo na configpasta. Apenas edite

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

para

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

e deve funcionar, embora você não consiga armazenar caracteres multibyte estendidos, como emoji .

Eu fiz isso com o Laravel 5.7. Espero que ajude.

Koushik Das
fonte
5
O uso desse conjunto de caracteres permitirá que você salve apenas caracteres ASCII padrão, e não caracteres especiais de vários bytes, como os de árabe, hebraico, a maioria dos scripts europeus e, é claro, emoji. veja também stackoverflow.com/a/15128103/4233593
Jeff Puckett
7
Eu acho que você perdeu essa parte use Illuminate\Support\Facades\Schema;no topo.
Pimpace
@KoushikDas que versão do Laravel você está usando?
Pimpace
Agora estou no 6.0. Eu acho que fiz isso inicialmente com 5.7 ou 5.6 talvez.
Koushik Das
2
O utf8mb4agrupamento existe por um motivo, eu recomendo usá-lo, se puder.
Chama
85

Estou apenas adicionando esta resposta aqui, pois é a quickestsolução para mim. Basta definir o motor de banco de dados padrão para 'InnoDB'a

/config/database.php

'mysql' => [
    ...,
    ...,
    'engine' => 'InnoDB',
 ]

em seguida, execute php artisan config:cachepara limpar e atualizar o cache de configuração

Dexter Bengil
fonte
1
Esta deve ser a resposta / solução oficial para esta pergunta ... Obrigado #
Syamsoul Azrien
1
Esta é a solução real, outras são soluções alternativas
Luís Cunha
3
mas qual é a lógica por trás disso
Zulfiqar Tariq
1
Essa é a solução correta. Mas por que não foi incluído na instalação padrão.
Ankit Chauhan
38

No AppServiceProvider.php, você inclui esse código na parte superior do arquivo.

use Illuminate\Support\Facades\Schema;

public function boot()
{
Schema::defaultStringLength(191);
}
user7688086
fonte
Obrigado me ajudou
The Dead Man
24

Esse problema é causado no Laravel 5.4 pela versão do banco de dados.

De acordo com os documentos (na Index Lengths & MySQL / MariaDBseção):

O Laravel usa o utf8mb4 conjunto de caracteres por padrão, que inclui suporte para armazenar "emojis" no banco de dados. Se você estiver executando uma versão do MySQL mais antiga que a versão 5.7.7 ou MariaDB mais antiga que a 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 do seu AppServiceProvider.

Em outras palavras, em <ROOT>/app/Providers/AppServiceProvider.php:

// Import Schema
use Illuminate\Support\Facades\Schema;
// ...

class AppServiceProvider extends ServiceProvider
{

public function boot()
{
    // Add the following line
    Schema::defaultStringLength(191);
}

// ...

}

Mas como o comentário da outra resposta diz:

Tenha cuidado com esta solução. Se você indexar campos de email, por exemplo, os emails armazenados podem ter apenas um comprimento máximo de 191 caracteres. Isso é menor do que os estados oficiais da RFC.

Portanto, a documentação também propõe outra solução:

Como alternativa, você pode ativar a innodb_large_prefixopção para o seu banco de dados. Consulte a documentação do seu banco de dados para obter instruções sobre como habilitar corretamente esta opção.

Esteban Herrera
fonte
16

Para alguém que não quer mudar AppServiceProvider.php. (Na minha opinião, é uma má ideia mudarAppServiceProvider.php apenas para migração)

Você pode adicionar novamente o comprimento dos dados ao arquivo de migração, database/migrations/conforme abaixo:

create_users_table.php

$table->string('name',64);
$table->string('email',128)->unique();

create_password_resets_table.php

$table->string('email',128)->index();
helloroy
fonte
Isso pode ser um problema, pois os e-mails podem ter até 255 caracteres (ish)
Half Crazed
Você está certo @HalfCrazed, mas eu sugiro que esta resposta stackoverflow.com/questions/1297272
helloroy
meu problema exatamente era solucionável por esta solução. Meus campos não eram e-mails.
Tharaka Devinda 28/09/19
11

Se você enfrentar esse erro enquanto trabalha no laravel enquanto usa o comando: php artisan migrate basta adicionar 2 linhas no arquivo: app-> Providers-> AppServiceProvider.php

  1. use Schema;
  2. Schema::defaultStringLength(191);

por favor verifique esta imagem . depois execute o php artisan migratecomando novamente.

Abdul Rasheed
fonte
1
é muito importante adicionar 'use Schema;'. Portanto, esta é a melhor resposta
hxwtch
Você também pode fazer isso em uma linha adicionando uma barra invertida '\' antes da 2ª linha como esta #\Schema::defaultStringLength(191);
Tahir Afridi
10

Estou adicionando duas soluções que funcionam para mim.

A primeira solução é :

  1. Abra o arquivo database.php na pasta / diretório de configuração .
  2. Editar 'engine' => null,para'engine' => 'InnoDB',

    Isso funcionou para mim.

A segunda solução é:

  1. Abra o arquivo database.php na pasta / diretório de configuração .
    2. Edite
    'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci',
    para

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


Boa sorte

Arslan Ahmad
fonte
10

atualize e insira essas linhas em app / Providers / AppServiceProvider.php

use Illuminate\Support\Facades\Schema;  // add this line at top of file

public function boot()
{
    Schema::defaultStringLength(191); // add this line in boot method
}
Anjani Barnwal
fonte
8

Resolvi esse problema e editei meu arquivo config-> database.php para gostar do meu banco de dados ('charset' => 'utf8') e do ('collation' => 'utf8_general_ci') , portanto, meu problema foi resolvido com o código como Segue:

'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' => 'utf8',
        'collation' => 'utf8_general_ci',
        'prefix' => '',
        'strict' => true,
        'engine' => null,
    ],
Ahmad Shakib
fonte
8

Encontrei duas soluções para este erro

OPÇÃO 1:

Abra sua tabela user e password_reset na pasta banco de dados / migrações

E basta alterar o tamanho do email:

$table->string('email',191)->unique();

OPÇÃO 2:

Abra seu app/Providers/AppServiceProvider.phparquivo e, dentro do boot()método, defina um tamanho de string padrão:

use Illuminate\Support\Facades\Schema;

public function boot()
{
    Schema::defaultStringLength(191);
}
Udhav Sarvaiya
fonte
7

1-/config/database.phpe encontre estas linhas

'mysql' => [
    ...,
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    ...,
    'engine' => null,
 ]

e altere-os para:

'mysql' => [
    ...,
    'charset' => 'utf8',
    'collation' => 'utf8_unicode_ci',
    ...,
    'engine' => 'InnoDB',
 ]

2- Execute php artisan config:cachepara reconfigurar o laravel

3- Exclua as tabelas existentes no seu banco de dados e execute php artisan migratenovamente

mohammad asghari
fonte
1
esta é a melhor resposta para o laravel 5.8. Mas exclua tabelas já criadas #
Magige Daniel 25/04/19
mas, de acordo com a documentação "utf8", o modo utf8 obsoleto será usado?
NoBugs 16/11/19
5

No arquivo AppServiceProvider.php :

 use Illuminate\Support\Facades\Schema;

public function boot()
{
    Schema::defaultStringLength(191);
}
Uddyan Semwal
fonte
5

Em vez de estabelecer um limite de comprimento, proporia o seguinte, que funcionou para mim.

Dentro:

config / database.php

substitua esta linha pelo mysql:

'engine' => 'InnoDB ROW_FORMAT=DYNAMIC',

com:

'engine' => null,
Md. Noor-A-Alam Siddique
fonte
4

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

use Illuminate\Support\Facades\Schema;

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

Nota: primeiro você deve excluir (se tiver) a tabela de usuários , a tabela password_resets do banco de dados e excluir as entradas de usuários e password_resets das migrações tabela de .

Para executar todas as suas migrações pendentes, execute o migratecomando Artisan:

php artisan migrate

Depois disso, tudo deve funcionar normalmente.

Dexter Bengil
fonte
4

Conforme já especificado, adicionamos ao AppServiceProvider.php em App / Providers

use Illuminate\Support\Facades\Schema;  // add this

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

você pode ver mais detalhes no link abaixo (pesquise "Comprimentos de índice e MySQL / MariaDB") https://laravel.com/docs/5.5/migrations

Mas bem, não é isso que publiquei! o problema é que, mesmo ao fazer o procedimento acima, você provavelmente obterá outro erro (é quando você executa o php artisan migratecomando e, devido ao problema do comprimento, a operação provavelmente ficará no meio. a solução está abaixo e a tabela do usuário provavelmente é criada sem o resto ou não totalmente correto) , precisamos reverter . 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 disso você está pronto para ir

php artisan migrate:rollback

php artisan migrate

Mohamed Allal
fonte
4

A solução que ninguém diz é que no Mysql v5.5 e posterior o InnoDB é o mecanismo de armazenamento padrão que não apresenta esse problema, mas em muitos casos como o meu, existem alguns arquivos de configuração antigos do mysql ini que usam o antigo mecanismo de armazenamento MYISAM como abaixo.

default-storage-engine=MYISAM

que está criando todos esses problemas e a solução é alterar o mecanismo de armazenamento padrão para o InnoDB no arquivo de configuração ini do Mysql de uma vez por todas, em vez de fazer hacks temporários.

default-storage-engine=InnoDB

E se você estiver no MySql v5.5 ou posterior, o InnoDB é o mecanismo padrão, portanto você não precisa defini-lo explicitamente como acima, apenas remova o default-storage-engine=MYISAMse ele existir no seu iniarquivo e você estará pronto .

Ali A. Dhillon
fonte
Obrigado! Eu tive que usar essa sugestão em conjunto com as mudanças de comprimento, conjunto de caracteres e agrupamento de strings para que isso funcionasse com o laravel 6 e o ​​mysql 5.6. Espero que isso ajude outras pessoas no futuro.
Casper Wilkes
@CasperWilkes, você não precisa fazer nada desse comprimento de string, do conjunto de caracteres. Verifique sua variável de sistema Mysql como esta, show global variables like 'innodb_large_prefix';ela deve estar LIGADA . Se estiver desativado , você pode verificar esta resposta sobre como ativá-lo. E aqui estão mais informações sobre innodb_large_prefix em dev.mysql.com.
Ali A. Dhillon 17/03
3

Se você deseja alterar no AppServiceProvider, precisa definir o comprimento do campo de email na migração. basta substituir a primeira linha de código pela segunda linha.

create_users_table

$table->string('email')->unique();
$table->string('email', 50)->unique();

create_password_resets_table

$table->string('email')->index();
$table->string('email', 50)->index();

Após as alterações bem-sucedidas, você pode executar a migração.
Nota: primeiro você deve excluir (se tiver) a tabela de usuários , a tabela password_resets do banco de dados e excluir as entradas de usuários e password_resets da tabela de migração.

Chintan Kotadiya
fonte
3

Schema::defaultStringLength(191);definirá o tamanho de todas as strings 191 por padrão, o que pode arruinar seu banco de dados. Você não deve ir por esse caminho.

Basta definir o comprimento de qualquer coluna específica na classe de migração do banco de dados. Por exemplo, estou definindo "nome", "nome de usuário" e "email" na CreateUsersTableclasse, como abaixo:

public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name', 191);
            $table->string('username', 30)->unique();
            $table->string('email', 191)->unique();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }
Fatema T. Zuhora
fonte
1
Isso é preferível para mim, pois eu prefiro não ajustar nenhum código principal do Laravel.
Okiemute Omuta
2

Isso é comum, pois o Laravel 5.4 alterou o caractere padrão do banco de dados definido para utf8mb4. O que você precisa fazer é: editar seu App \ Providers.php colocando esse código antes da declaração da classe

use Illuminate\Support\Facades\Schema;

Além disso, adicione isso à função 'boot' Schema::defaultStringLength(191);

Tesouro
fonte
2

Se você ainda não possui nenhum dado atribuído ao seu banco de dados, faça o seguinte:

  1. Vá para app / Providers / AppServiceProvide.php e adicione

use Illuminate \ Support \ ServiceProvider;

e dentro do método boot ();

Esquema :: defaultStringLength (191);

  1. Agora exclua os registros em seu banco de dados, tabela de usuários para ex.

  2. execute o seguinte

php artisan config: cache

artesão php migrar

Levinski Polish
fonte
Funcionou, mas precisa adicionar use Illuminate\Support\Facades\Schema; use Illuminate\Support\ServiceProvider;já está lá. Espero que você corrigi-lo
Jimish Gamit
2

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:

//edit your AppServiceProvider.php file contains in providers folder
use Illuminate\Support\Facades\Schema;

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

Espero que isso ajude você .. cheers ..

Rohit Saini
fonte
2

Acabei de modificar a seguinte linha userse password_resetsarquivo de migração.

Velho : $table->string('email')->unique();

Novo : $table->string('email', 128)->unique();

Mahesh Gaikwad
fonte
1

Para evitar alterar qualquer coisa em seu código , simplesmente atualize seu servidor MySQL para pelo menos 5.7.7

Consulte isso para obter mais informações: https://laravel-news.com/laravel-5-4-key-too-long-error

FE Noel Nfebe
fonte
Não, o Mariadb 10.1.41 em 18.04 também possui esse erro.
NoBugs 16/11/19
1

Eu acho que forçar a StringLenght a 191 é uma péssima idéia. Então, eu investigo para entender o que está acontecendo.

Percebi que esta mensagem de erro:

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

Comecei a aparecer depois que atualizei minha versão do MySQL. Portanto, verifiquei as tabelas com o PHPMyAdmin e notei que todas as novas tabelas criadas estavam com o agrupamento utf8mb4_unicode_ci em vez de utf8_unicode_ci para as antigas.

No meu arquivo de configuração da doutrina, notei que o charset estava definido como utf8mb4, mas todas as minhas tabelas anteriores foram criadas no utf8, então acho que essa é uma mágica de atualização que começa a funcionar no utf8mb4.

Agora, a solução mais fácil é alterar o conjunto de caracteres de linha no seu arquivo de configuração do ORM. Em seguida, descarte as tabelas usando utf8mb4_unicode_ci se você estiver no modo dev ou corrija o charset se não puder descartá-las.

Para Symfony 4

mude charset: utf8mb4 para charset: utf8 em config / packages / doctrine.yaml

Agora, minhas migrações de doutrina estão funcionando novamente muito bem.

Kaizoku Gambare
fonte
1

A solução recomendada é habilitar innodb_large_prefix opção do MySQL para que você não entre em problemas subseqüentes. E aqui está como fazer isso:

Abra o my.iniarquivo de configuração do MySQL e adicione as linhas abaixo sob a [mysqld]linha como esta.

[mysqld]
innodb_file_format = Barracuda
innodb_large_prefix = 1
innodb_file_per_table = ON

Depois disso, salve as alterações e reinicie o serviço MySQL.

Faça o retrocesso, se necessário, e execute novamente a migração.


Caso seu problema persista, vá para o arquivo de configuração do banco de dados e defina

'engine' => null, para 'engine' => 'innodb row_format=dynamic'

Espero que ajude!

Sammie
fonte
1

primeiro exclua todas as tabelas do banco de dados no host local

Altere as propriedades do banco de dados padrão do Laravel (utf8mb4) no arquivo config / database.php para:

'charset' => 'utf8', 'agrupamento' => 'utf8_unicode_ci',

depois disso Alterando minhas propriedades do banco de dados local utf8_unicode_ci. artesão php migrar está tudo bem.

Goldman.Vahdettin
fonte
0

Para qualquer outra pessoa que possa se deparar com isso, meu problema é que eu estava criando uma coluna do tipo stringe tentando fazê-la ->unsigned()quando pretendia que fosse um número inteiro.

Brynn Bateman
fonte
0

O trabalho abordado aqui foi passar um segundo parâmetro com o nome da chave (um nome curto):

$table->string('my_field_name')->unique(null,'key_name');
Tiago Gouvêa
fonte
0

Eu estava recebendo esse erro, embora já tivesse (na verdade, porque já tinha) Schema :: defaultStringLength (191); no meu arquivo AppServiceProvider.php.

O motivo é que eu estava tentando definir um valor de sequência em uma das minhas migrações para um valor maior que 191:

Schema::create('order_items', function (Blueprint $table) {
    $table->primary(['order_id', 'product_id', 'attributes']);
    $table->unsignedBigInteger('order_id');
    $table->unsignedBigInteger('product_id');
    $table->string('attributes', 1000); // This line right here
    $table->timestamps();
});

Remover o 1000 ou defini-lo como 191 resolveu meu problema.

Jacey
fonte