Laravel迁移:即使指定,唯一键也太长


165

我正在尝试迁移Laravel中的用户表。当我运行迁移时,出现以下错误:

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

我的迁移如下:

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

经过一番谷歌搜索后,我发现了这个错误报告,泰勒说您可以将索引键指定为的第二个参数unique(),这已经完成了。它仍然给出错误。这里发生了什么?


为什么要使用320个字符的电子邮件?这可能是您的问题。
安东尼奥·卡洛斯·里贝罗

1
那确实是问题,不知道为什么。但是,是的,您是对的,我不知道为什么我为每个字段指定字符长度。取消了这些限制
哈利

有趣的是,没有人建议使用包含电子邮件和内容哈希的固定长度字段-对于任何框架和任何关系数据库来说,永远解决的问题。因为这就是我们保证唯一性的方式-考虑到数字范围足够大(对于sha1 / sha256是这样),使用可变长度输入的固定数字表示形式。
NB


Answers:


280

为您的电子邮件指定一个较小的长度:

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

实际上是默认值:

$table->string('email');

而且你应该很好。

对于Laravel 5.4,您可以在此Laravel 5.4中找到解决方案:指定密钥太长错误,Laravel新闻发布:

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

use Illuminate\Database\Schema\Builder;


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

6
因此,最大可能的电子邮件长度254值得牢记这一点,因此在这种情况下,我可能会使用验证器来验证唯一性。
塞巴斯蒂安·苏林斯基'17

12
对于Laravel 5.4,请使用\Illuminate\Database\Schema\Builder::defaultStringLength(191);正确的函数引用路径
Webcoder

5
在AppServiceProvider.php中进行配置后,此问题仍在发生。我很困惑。为什么?我重新启动了服务器,数据库以及所有内容,但仍然如此。请帮忙。
Koushik Das

3
您必须根据767个字节的限制设置索引列的长度。请注意,每个长度单位的VARCHAR可能有1、2或4个字节。示例:utf8_mb4(4字节)-> 767/4 =191。否则,对于VARCHAR(X),utf8_general_ci对于X <85(1个字节)= O(85);对于VARCHAR(X),utf8_general_ci对于X> = 86(2 bytes)-> 767/2 =383。还要考虑多个列索引中的其他列长度。
Jackie Degl'Innocenti

2
您可能还想通过为所有字符串列指定默认长度来直接编辑迁移文件中特定列的长度,因为并非所有列都需要此约束,因为它们不在任何索引中。$ table-> string('column_name',191);
Jackie Degl'Innocenti

109

更新1

Laravel 5.4开始,不再需要这些更改。

Laravel 5.4默认使用utf8mb4字符集,该字符集支持在数据库中存储“表情符号”。如果要从Laravel 5.3升级应用程序,则无需切换到此字符集。

更新2

当前默认情况下,当前生产的MariaDB版本支持此设置。默认情况下,它在MariaDB 10.2.2+中实现。

并且,如果您有意要使用正确的Future-default(从Laravel 5.4开始)对的UTF8多字节utf8mb4支持,请开始修复😂您的数据库配置。

在Laravel中config/database.php定义:

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

DYNAMIC允许存储长键索引。

服务器设置(默认情况下包含在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

对于客户:

[mysql]
default-character-set=utf8mb4

然后停止您的MySQL / MariaDB服务器。在那之后开始。热重启可能不起作用。

sudo systemctl stop mysqld
sudo systemctl start mysqld

现在,您有了具有UTF8支持的Laravel5.x。


3
这对于MySQL 5.5可能已经足够好了(没有尝试重新配置)。5.7(可能也是5.6)可以工作,而无需任何重新配置​​。5.7是具有原始配置的默认Community Server发行版。
Pjotr​​ '16

正如您提到的,我在我的database.php中更改了引擎,但是它仍在创建具有row = compact的表,这导致了问题。我不完全了解,您是说仅在database.php中进行此更改是不够的,还需要在my.cnf文件中进行更改吗?
vesperknight

仅在database.php配置文件中进行更改就足够了,它将影响本地Laravel项目。delete进行更改之前,请确保先数据库化并使用新设置进行创建。您仅需要my.cnf为全局服务器端更改(当前所有新安装都使用utf8mb4)更改配置文件。
得分手

或者-添加另一个字段,计算电子邮件的哈希值,使该字段唯一,永远解决问题,避免摆弄数据库初始化变量。
NB

如果有人使用Doctrine 2,则可以通过传递options={"row_format"="DYNAMIC"}@Table注释来设置ROW_FORMAT 。
艾伯特221 '02

50

如果您正在使用Laravel 5.4或已更新至Laravel 5.4,这对我有用。

只需1次更改。在AppServiceProvider.php中

use Illuminate\Support\Facades\Schema;

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

如迁移指南中所述https://laravel.com/docs/master/migrations#creating-indexes


我是在迁移本身上完成的。
阿米尔马苏德(Amirmasoud)

7
这(大概)是因为每个字符正好占据4个字节,并且最大密钥长度以字节为单位,而不是字符。因此,密钥长度将为191 * 4 = 764个字节,仅比数据库将支持的最大767个字节少一个smidgen。解决方案如果要在这里为共享知识做出贡献,而不仅仅是提供“程序”,则需要IMO的解释。但是仍然可以轻松解决。
杰森

33

如果其他人像我一样偶然发现了这个答案,但由于其他原因,则可以检查Laravel DB字符集/排序规则。

我正在安装应用程序(Snipe-IT),并已配置Laravel数据库配置以使用以下内容:

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

mb4从两个字符串中删除都可以解决此问题,尽管我相信Antonio的答案是真正解决问题的方法。



16

从charset删除mb4并从config / database.php中删除排序规则,然后它将成功执行。
'charset'=>'utf8',
'collat​​ion'=>'utf8_unicode_ci',


15

对于laravel 5.6,
此解决方案可解决我的问题,
请转到config/database.php
下面的代码中

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

更改这两个字段

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

有了这个

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

14

我遇到了同样的问题,并通过在我的app / database.php中添加以下两行来解决了该问题

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

我的文件如下所示:

<?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
如果您在Laravel中安装了新版本。请从utf8mb4和utf8mb4_unicode_ci&config / database.php中删除“ mb4”
Muthu17 '17

13

对于laravel 5.4,只需编辑文件

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
尽管这可以回答问题,但最好添加一些有关此回答如何有助于解决问题的描述。请阅读我如何写一个好的答案以了解更多信息。
Roshana Pitigala

6

我有同样的问题,我正在使用一个沼泽

解决方案:打开文件:config / database.php

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

谢谢


先前的答案对我来说都没有用,但是这个答案就像一个魅力!而且这很合理,我相信在以前的Laravel DB引擎版本中,默认情况下将其设置为InnoDB,因此我们以前没有遇到这些错误。
Sasa Blagojevic,

是的,还需要做几个其他的答案,这也是。
安德鲁

6

在文件config / database.php中,其中:

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

将此行更改为此:

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

5

对于Laravel> = 5.6用户

开启AppServiceProvider.php档案

使用以下课程

use Illuminate\Support\Facades\Schema;

然后在boot方法内部添加以下行

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

4

我添加了迁移本身

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

是的,我知道我需要在每次迁移时都进行考虑,但我宁愿将其隐藏在一些完全不相关的服务提供商中


4

如果某人甚至在执行此操作后仍然遇到此问题,上述内容也会发生变化。例如,在我的情况下,我做了以下更改,

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

但是由于两个原因,它不会立即生效。一种是如果您使用流明而非laravel,则可能必须先在app.php文件中取消注释此行。

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

然后,您必须使用artisan命令再次创建迁移脚本,

php artisan make:migration <your_table_name>

从现在开始,仅您对ServiceProvider所做的更改将起作用。




2

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

use Illuminate\Support\Facades\Schema;

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

您可以签出

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


谢谢,为我工作。甲基苯丙胺的MySQL与laravel 23年6月5日
蓝天

2

这是因为Laravel 5.4使用支持存储表情符号的utf8mb4

将此添加到您的app \ Providers \ AppServiceProvider.php中

use Illuminate\Support\Facades\Schema;

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

而且你应该很好走。


2

如果您正在使用Laravel 5.4或已更新至最新版本,则可以使用;
AppServiceProvider.php中只有1次更改

use Illuminate\Support\Facades\Schema;

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

1

我想指出我错过的一些事情...

我是Laravel的新手,我没有复制“ use Illuminate .....”,因为我确实没有引起注意,因为在功能启动上方,您已经有一个use语句。

希望对任何人有帮助

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

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

您也可以在任何Facade前面添加前缀\
Ohgodwhy,


1

2016年10月24日,泰勒·奥特威尔(Taylor Otwell)宣布了《拉拉维尔》的作者是Twitter

“ utf8mb4”将是Laravel 5.4中的默认MySQL字符集,以更好地支持表情符号。🙌 泰勒·奥特威尔(Twitter)

在5.4版之前,字符集是 utf8

在本世纪中,许多网络应用程序(包括聊天程序或某种允许用户交流的平台),许多人喜欢使用表情符号或笑脸。这是某种超级字符,需要存储更多的空间,只能utf8mb4作为字符集使用。这就是为什么他们迁移到utf8mb4太空的原因。

如果您在Illuminate\Database\Schema\Builder班级中查找,则会看到将$defaultStringLength设置为255,并进行修改可以继续通过SchemaFacade并调用defaultStringLength方法并传递新的长度。

要执行该更改,请在您的AppServiceProvider类中的app \ providers子目录下调用该方法,如下所示

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
}

我建议使用191作为值,因为MySQL支持767个字节,并且因为767 / 4这是每个多字节字符所占用的字节数191

您可以在此处了解更多信息 utf8mb4字符集(4字节UTF-8 Unicode编码) 对表列数和行大小的限制


这是解释191幻数的唯一答案。
Illya Moskvin



0

如果您使用的是MySQL 5.7.7+或MariaDB 10.2.2+,则不会出现此问题。

要使用啤酒先取消当前的Mac上更新MariaDB的: brew unlink mariadb然后使用安装一个开发一个brew install mariadb --devel

安装完成后,停止/启动运行的服务: brew services stop mariadb brew services start mariadb

当前的开发版本是10.2.3。安装完成后,您将不必再为此担心,您可以使用utf8mb4(现在是Laravel 5.4中的默认设置),而无需切换回utf8或按照Laravel文档中的建议编辑AppServiceProvider: https:// laravel .com / docs / master / releases#laravel-5.4(向下滚动至:Migration Default String Length


0

刚安装了MariaDB 10.2.4 RC,启动了新的空白Laravel 5.4项目,并进行了默认迁移(varchar(255)列)。

无需更改DB conf和Laravael config/database.php。因此,就像@scorer指出的关于10.2.2+的默认行为一样。


0

所有这些在其他Anwser中都有很好的描述,您可以在下面的链接中查看更多详细信息(使用键“ Index Lengths&MySQL / MariaDB”进行搜索) https://laravel.com/docs/5.5/migrations

但是,这不是这个答案的意思!即使执行上述操作,仍然会遇到另一个错误(这是因为您喜欢启动php artisan migrate命令,并且由于长度问题,操作像卡在中间一样。解决方案是bellow,而用户表就像没有其余的还是不完全正确的), 我们需要进行bac k。默认回滚将不起作用。因为迁移操作不喜欢完成。您需要手动删除数据库中新创建的表。

我们可以像下面这样使用修补匠来做到这一点:

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

0

设置数据库引擎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

如果您尝试过其他所有答案,但都无法解决问题,则可以从数据库中删除所有表,然后使用此命令一次全部执行migration命令:

php artisan migrate:fresh
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.