Laravel迁移错误:语法错误或访问冲突:1071指定的密钥太长;最大密钥长度为767字节


176

Laravel 5.4上的迁移错误 php artisan make:auth

[Illuminate \ Database \ QueryException] SQLSTATE [42000]:语法错误或访问冲突:1071指定的密钥太长;默认值为0。最大密钥长度为767字节(SQL:更改表users添加唯一users_email_uniqueemail))

[PDOException] SQLSTATE [42000]:语法错误或访问冲突:1071指定的密钥太长;默认值为0。最大密钥长度为767字节


3
您应该在答案中回答您的问题。没问题。stackoverflow.com/help/self-answer
Can Vural

感谢@ can-vural的建议,我做到了。
absiddiqueLive

Answers:


281

根据官方文档,您可以轻松解决此问题。

将以下两行代码添加到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
}

MySQL始终将UTF8字段的最大数量保留为4个字节,因此使用DEFAULT CHARACTER SET 255 + 255时为utf8mb4 COLLATE utf8mb4_unicode_ci; 您超出了767最大密钥长度限制。通过@scaisedge


2
请注意此解决方案。例如,如果您为电子邮件字段编制索引,则存储的电子邮件的最大长度只能为191个字符。这少于官方的RFC规定。
shock_gone_wild


它正在工作并且是一个有效的解决方案,但是我只想指出,使用这种方法可能存在陷阱。
shock_gone_wild

我希望这种解决方案将来不会对我产生影响,但是目前,这种方法行之有效。不过,我必须谨慎对待如何为电子邮件编制索引。
deusofnull

4
为什么恰好有191个字符@absiddiqueLive
PseudoAj

120

我不知道为什么上述解决方案和正在添加的官方解决方案

Schema::defaultStringLength(191);

AppServiceProvider对我不起作用。起作用的是编辑database.php文件config夹中的文件。只是编辑

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

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

并且它应该可以工作,尽管您将无法存储扩展的多字节字符(如表情符号)

我使用Laravel 5.7做到了。希望能帮助到你。


5
使用此字符集将只允许您保存标准ASCII,而不能保存多字节特殊字符,例如阿拉伯,希伯来语,大多数欧洲脚本中的字符,当然还有表情符号。另请参阅stackoverflow.com/a/15128103/4233593
Jeff Puckett

7
我认为您错过use Illuminate\Support\Facades\Schema;了顶部的这一部分。
pimpace

@KoushikDas您正在使用哪个版本的Laravel?
pimpace

现在我是6.0。我想我最初是用5.7或5.6做到的。
Koushik Das

2
utf8mb4整理是有原因的,我建议,如果你能使用它。
Flame

85

我只是在这里添加此答案,因为这是quickest我的解决方案。只需将默认数据库引擎设置为'InnoDB'on

/config/database.php

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

然后运行php artisan config:cache以清除并刷新配置缓存


1
这应该是这个问题的正式答案/解决方案...谢谢
Syamsoul Azrien

1
这是实际的解决方案,其他的变通办法
路易斯·库尼亚

3
但背后的逻辑是什么
Zulfiqar Tariq

1
那是正确的解决方案。但是,为什么不将它包含在默认安装中。
Ankit Chauhan

38

在中AppServiceProvider.php,您将此文件顶部的代码包括在内。

use Illuminate\Support\Facades\Schema;

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

谢谢帮助我
死者

23

此问题是由数据库版本在Laravel 5.4中引起的。

根据文档(在Index Lengths & MySQL / MariaDB部分中):

Laravel utf8mb4默认使用字符集,该字符集支持在数据库中存储“表情符号”。如果您运行的MySQL版本低于5.7.7发行版或MariaDB版本低于10.2.2版本,则可能需要手动配置迁移生成的默认字符串长度,以便MySQL为它们创建索引。您可以通过在中调用Schema::defaultStringLength方法来配置它 AppServiceProvider

换句话说<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);
}

// ...

}

但是正如对其他答案的评论所说:

请注意此解决方案。例如,如果您为电子邮件字段编制索引,则存储的电子邮件的最大长度只能为191个字符。这少于官方的RFC规定。

因此,文档还提出了另一种解决方案:

或者,您可以innodb_large_prefix为数据库启用该选项。有关如何正确启用此选项的说明,请参考数据库的文档。


16

对于不想改变的人AppServiceProvider.php。(我认为,进行更改不是一个好主意AppServiceProvider.php仅针对迁移是个)

您可以通过以下方式将数据长度添加回迁移文件database/migrations/

create_users_table.php

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

create_password_resets_table.php

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

这可能是一个问题,因为电子邮件最多可以包含255个(ish)字符

您说得对@HalfCrazed,但我建议这个答案stackoverflow.com/questions/1297272
helloroy

这个解决方案可以解决我的问题。我的字段不是电子邮件。
Tharaka Devinda

11

如果在使用命令时在laravel上工作时遇到此错误:php artisan migrate 则只需在文件中添加两行:app-> Providers-> AppServiceProvider.php

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

请检查这张图片。然后php artisan migrate再次运行命令。


1
添加“使用模式”非常重要。所以这是最好的答案
hxwtch '19

您也可以通过在第二行之前添加反斜杠'\'来做到这一点,就像这样\Schema::defaultStringLength(191);
Tahir Afridi

10

我要添加两种对我有用的解决方案。

第一种解决方案是

  1. 打开database.php文件insde 配置 dir / folder中的。
  2. 编辑 'engine' => null,'engine' => 'InnoDB',

    这对我有用。

第二种解决方法是:

  1. 打开insde config dir / folder中的database.php文件。 2. 编辑

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

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


祝好运


10

更新这些行并将其插入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
}

8

我已经解决了这个问题,并编辑了config-> database.php文件,使其与数据库('charset'=>'utf8')('collat​​ion'=>'utf8_general_ci')类似,因此我的问题解决了跟随:

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

8

我已找到此错误的两种解决方案

选项1:

数据库/迁移中打开用户password_reset文件夹中

只需更改电子邮件的长度即可:

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

选项2:

打开app/Providers/AppServiceProvider.php文件,并在boot()方法中设置默认字符串长度:

use Illuminate\Support\Facades\Schema;

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

7

1-转到/config/database.php并找到这些行

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

并将它们更改为:

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

2-运行php artisan config:cache以重新配置laravel

3-删除数据库中的现有表,然后php artisan migrate再次运行


1
这是laravel 5.8的最佳答案。但是删除已创建的表
Magige Daniel

但是根据文档“ utf8”会使用不推荐使用的utf8模式吗?
NoBugs

5

AppServiceProvider.php文件中:

 use Illuminate\Support\Facades\Schema;

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

5

我不建议设置长度限制,而是建议以下对我有用的方法。

内:

config / database.php

将此行替换为mysql:

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

与:

'engine' => null,

4

正如已经指定的,我们在App / Providers中添加到AppServiceProvider.php

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

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

您可以在下面的链接中查看更多详细信息(搜索“索引长度和MySQL / MariaDB”) https://laravel.com/docs/5.5/migrations

但是那不是我发表的全部!问题是即使执行上述操作,您也可能会遇到另一个错误(即在运行php artisan migrate命令时,由于长度问题,操作可能会卡在中间。解决方案在以下,并且可能创建了用户表没有其他内容或没有完全正确), 我们需要回退。默认回滚将不起作用。因为迁移操作不喜欢完成。您需要手动删除数据库中新创建的表。

我们可以使用修补程序来做到这一点,如下所示:

L:\todos> php artisan tinker

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

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

=> null

我本人对用户表有问题。

在那之后你很好

php artisan migrate:rollback

php artisan migrate


4

没有人知道的解决方案是,在Mysql v5.5和更高版本中,InnoDB是没有此问题的默认存储引擎,但是在许多情况下,例如我的,有一些旧的mysql ini配置文件正在使用旧的MYISAM存储引擎,如下所示。

default-storage-engine=MYISAM

这就造成了所有这些问题,解决方案是一劳永逸地将Mysql的ini配置文件中的default-storage-engine更改为InnoDB,而不是进行临时性修改。

default-storage-engine=InnoDB

而且,如果您使用的是MySql v5.5或更高版本,则InnoDB是默认引擎,因此您无需像上面那样显式设置它,只需default-storage-engine=MYISAMini文件中删除if存在,就可以了。


谢谢!我必须结合字符串长度,字符集和排序规则更改来使用此建议,以便使其与laravel 6和mysql 5.6一起使用。希望这对将来有帮助。
卡斯珀·威尔克斯

@CasperWilkes您不必执行任何字符串长度的字符集设置。像这样检查您的Mysql系统变量,show global variables like 'innodb_large_prefix';它应该为ON。如果关闭,则可以检查答案的开启方式。而这里是关于dev.mysql.com innodb_large_prefix更多信息。
Ali A. Dhillon

3

如果要在AppServiceProvider中进行更改,则需要在迁移中定义电子邮件字段的长度。只需将第一行代码替换为第二行即可。

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

成功更改后,您可以运行迁移。
注意:首先,您必须从数据库中删除(如果有)用户表password_resets表,并从迁移表中删除用户和password_resets条目。


3

如要解决此问题的《迁移指南》中概述的那样,您所需要做的就是编辑app/Providers/AppServiceProvider.php文件,并在启动方法中设置默认字符串长度:

use Illuminate\Support\Facades\Schema;

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

注意:首先,您必须从数据库中删除(如果有)用户表,password_resets表,并从迁移表中删除用户和password_resets条目。

要运行所有未完成的迁移,请执行migrateArtisan命令:

php artisan migrate

之后,一切都应正常进行。


3

Schema::defaultStringLength(191);将默认定义所有字符串191的长度,这可能会破坏数据库。你一定不要这样。

只需在数据库迁移类中定义任何特定列的长度即可。例如,我在类中定义“名称”,“用户名”和“电子邮件”,CreateUsersTable如下所示:

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

1
这对我来说是最可取的,因为我不想调整任何Laravel核心代码。
Okiemute大牟田

2

这是很常见的,因为Laravel 5.4将默认数据库字符设置更改为utf8mb4。您需要做的是:通过在类声明之前放置此代码来编辑App \ Providers.php

use Illuminate\Support\Facades\Schema;

另外,将其添加到“启动”功能 Schema::defaultStringLength(191);


2

如果尚未为数据库分配任何数据,请执行以下操作:

  1. 转到app / Providers / AppServiceProvide.php并添加

使用Illuminate \ Support \ ServiceProvider;

并在方法boot()内部;

架构:: defaultStringLength(191);

  1. 现在,删除数据库中的记录,例如用户表。

  2. 运行以下

php artisan config:缓存

PHP的工匠迁移


它起作用了,但是需要添加 use Illuminate\Support\Facades\Schema; use Illuminate\Support\ServiceProvider;了。希望你改正
Jimish GAMIT

2

正如要解决此问题的《迁移指南》中概述的那样,您要做的就是编辑AppServiceProvider.php文件,并在启动方法中设置默认字符串长度:

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

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

希望这会对您有所帮助。




1

我认为将StringLenght强制为191是一个非常糟糕的主意。因此,我进行调查以了解发生了什么。

我注意到此消息错误:

SQLSTATE [42000]:语法错误或访问冲突:1071指定的密钥太长;默认值为0。最大密钥长度为767字节

更新MySQL版本后开始显示。因此,我已经使用PHPMyAdmin检查了表,并且注意到所有创建的新表都使用排序规则utf8mb4_unicode_ci而不是utf8_unicode_ci旧。

在我的配置文件中,我注意到charset设置为utf8mb4,但是我以前的所有表都是在utf8中创建的,所以我想这是一些更新魔术,它可以在utf8mb4上开始工作。

现在,简单的解决方法是更改​​ORM配置文件中的行字符集。然后,如果您处于开发人员模式,则使用utf8mb4_unicode_ci删除表;如果无法删除它们,则修复字符集。

对于Symfony 4

改变字符集:utf8mb4字符集:UTF-8配置/包/ doctrine.yaml

现在,我的学说迁移再次正常进行。


1

推荐的解决方案是启用 innodb_large_prefix MySQL选项,这样您就不会陷入后续问题。这是这样做的方法:

打开my.iniMySQL配置文件,并在下面的行中添加以下行[mysqld]

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

之后,保存您的更改并重新启动MySQL服务。

如果需要回滚,然后重新运行迁移。


万一您的问题仍然存在,请转至数据库配置文件并进行设置

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

希望能帮助到你!


1

首先删除本地主机中数据库的所有表

将config / database.php文件中的Laravel默认数据库(utf8mb4)属性更改为:

'charset'=>'utf8','collat​​ion'=>'utf8_unicode_ci',

之后,更改我的本地数据库属性utf8_unicode_ci。php artisan迁移也可以。


0

对于可能遇到此问题的任何其他人,我的问题是我正在创建类型为type的列,string->unsigned()在我打算将其作为整数时尝试创建它。



0

即使我已经有了(实际上是因为我已经有了)Schema :: defaultStringLength(191);,我仍然收到此错误。在我的AppServiceProvider.php文件中。

原因是因为我试图在一次迁移中将字符串值设置为大于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();
});

删除1000或将其设置为191解决了我的问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.