【问题标题】:Laravel migration: unique key is too long, even if specifiedLaravel 迁移:唯一键太长,即使指定
【发布时间】:2014-07-10 06:47:19
【问题描述】:

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

[Illuminate\Database\QueryException] SQLSTATE[42000]:语法错误 或访问冲突:1071 指定的密钥太长;最大密钥长度 为 767 字节(SQL:alter table users add unique 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');
});

经过一番谷歌搜索后,我遇到了this bug report,Taylor 说您可以将索引键指定为unique() 的第二个参数,我已经这样做了。它仍然给出错误。这是怎么回事?

【问题讨论】:

  • 您为什么使用 320 个字符的电子邮件?这可能是你的问题。
  • 确实是这个问题,不知道为什么。但是,是的,你是对的,我不知道为什么我为每个字段指定了字符长度。已取消这些限制
  • 有趣的是,没有人建议使用包含电子邮件哈希的固定长度字段,瞧——对于任何框架和任何关系数据库,问题都永远解决了。因为这就是我们保证唯一性的方式——使用可变长度输入的固定数字表示,因为数字范围足够大(对于 sha1 / sha256 也是如此)。

标签: php mysql laravel migration unique-key


【解决方案1】:

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

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

实际上是默认的:

$table->string('email');

你应该很好。

对于 Laravel 5.4,您可以在 Laravel 5.4: Specified key was too long error, Laravel News 帖子中找到解决方案:

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

use Illuminate\Database\Schema\Builder;


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

【讨论】:

  • 最大可能的电子邮件长度是254,所以可能值得记住这一点,所以在这种情况下我可能会使用验证器来验证唯一性。
  • 对于 Laravel 5.4,使用 \Illuminate\Database\Schema\Builder::defaultStringLength(191); 获取正确的函数引用路径
  • 在AppServiceProvider.php中进行配置后,还是出现这个问题。我只是困惑。为什么?我重新启动了服务器、数据库和一切,但仍然如此。请帮忙。
  • 您必须根据767字节的限制设置索引列的长度。请注意,VARCHAR 的每个长度单位可能有 1、2 或 4 个字节。示例:utf8_mb4 (4 bytes) -> 767 / 4 = 191. 否则 utf8_general_ci 用于 VARCHAR(X) 且 X = 86 ( 2 bytes ) -> 767 / 2 = 383。还要考虑多列索引中的其他列长度。
  • 您可能还想直接编辑迁移文件中特定列的长度,而不是为所有字符串列指定默认长度,因为并非所有列都需要此约束,因为它们不是在任何索引中。 $table->string('column_name',191);
【解决方案2】:

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

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

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

从两个字符串中删除 mb4 解决了这个问题,尽管我相信 Antonio 的回答是问题的真正解决方案。

【讨论】:

    【解决方案3】:

    更新 1

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

    Laravel 5.4 默认使用 utf8mb4 字符集,其中包括支持在数据库中存储“表情符号”。如果你从 Laravel 5.3 升级你的应用程序,你不需要切换到这个字符集。

    更新 2

    当前生产的 MariaDB 版本默认全局支持此设置。它在MariaDB 10.2.2+ by default中实现。

    解决方案

    如果您有意使用正确的 future-default(从 Laravel 5.4 开始)UTF8 多字节 utf8mb4 支持 ? 然后开始修复 ? 您的数据库配置。

    在 Laravel 中 config/database.php 定义:

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

    DYNAMIC 允许存储long key 索引。

    服务器设置(默认包含在 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 的 Laravel 5.x。

    【讨论】:

    • 这可能在 MySQL 5.5 中运行良好(没有尝试重新配置)。 5.7(可能也是 5.6)无需任何重新配置​​即可工作。 5.7 是带有 vanilla 配置的默认社区服务器发行版。
    • 我更改了我的 database.php 中的引擎,但它仍在使用 row=compact 创建表,这会导致问题。没完全看懂,你是说在database.php里做这个修改还不够,还需要修改my.cnf文件?
    • 只需在database.php 配置文件中进行更改就足够了,它将影响本地 Laravel 项目。确保在进行更改之前delete 数据库并使用新设置创建它。您需要更改 my.cnfconfig 文件仅用于全局服务器端更改(当前所有新安装都使用 utf8mb4)。
    • 或者 - 添加另一个字段,计算电子邮件的哈希,使字段唯一,永远解决问题,避免摆弄数据库初始化变量。
    • 如果有人使用 Doctrine 2,您可以通过将 options={"row_format"="DYNAMIC"} 传递给您的 @Table 注释来设置 ROW_FORMAT。
    【解决方案4】:

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

    要在 Mac 上使用 Brew 更新 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(滚动归结为:迁移默认字符串长度

    【讨论】:

      【解决方案5】:

      这对我有用:

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

      【讨论】:

      • 这对我有用。我使用服务器版本:10.1.22-MariaDB - 源码分布
      【解决方案6】:

      如果你正在使用或更新到 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中所述

      【讨论】:

      • 我在迁移本身上做了这个。
      • 这是(大概)因为每个字符正好占用 4 个字节,并且最大密钥长度以字节为单位,而不是字符。所以密钥长度将是 191 * 4 = 764 字节,仅比数据库支持的最大 767 字节少一点点。如果解决方案要为这里的共享知识做出贡献,而不仅仅是提供“程序”,则需要对 IMO 进行解释。但仍然是一个方便的修复。
      【解决方案7】:

      对于 laravel 5.4,只需编辑文件

      App\Providers\AppServiceProvider.php

      use Illuminate\Support\Facades\Schema;
      
      public function boot()
      {
          Schema::defaultStringLength(191);
      }
      

      【讨论】:

        【解决方案8】:

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

        【讨论】:

          【解决方案9】:

          我有同样的问题,我正在使用 wamp

          解决方案: 打开文件 : 配置/数据库.php

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

          谢谢

          【讨论】:

          • 之前的答案都没有对我有用,但这个答案就像一个魅力!这很有意义,我相信以前版本的 Laravel DB 引擎默认设置为 InnoDB,所以我们之前没有遇到这些错误。
          • 是的,需要做几个其他的答案,这个也是。
          【解决方案10】:

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

          无需更改 DB conf 和 Laravael config/database.php。因此,正如@scorer 提到的 10.2.2+ 的默认行为一样。

          【讨论】:

            【解决方案11】:

            我遇到了同样的问题,并通过在我的 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',
            
                ......
            

            【讨论】:

            • 如果你在 Laravel 中安装了新版本。请从 utf8mb4 & utf8mb4_unicode_ci & config/database.php 中删除“mb4”
            【解决方案12】:

            我添加到迁移本身

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

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

            【讨论】:

              【解决方案13】:

              将字符集从 'utf8mb4' 更改为 'utf8' 和

              将“utf8mb4_unicode_ci”归类为“utf8_unicode_ci”

              在 config/database.php 文件中

              它对我有用。

              【讨论】:

                【解决方案14】:

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

                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

                【讨论】:

                • 谢谢,为我工作。使用 laravel 5.6.23 映射 mysql
                【解决方案15】:

                在顶部包含这一行

                use Illuminate\Support\Facades\Schema;
                

                然后在启动函数里面添加这个

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

                【讨论】:

                • 您能否通过突出显示代码并按 Ctrl+K 来格式化您的代码
                【解决方案16】:

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

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

                use Illuminate\Support\Facades\Schema;
                
                public function boot()
                {
                    Schema::defaultStringLength(191);
                }
                

                你应该很高兴。

                【讨论】:

                  【解决方案17】:

                  在文件 config/database.php 中:

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

                  将此行更改为:

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

                  【讨论】:

                    【解决方案18】:

                    如果你正在使用或更新到 Laravel 5.4 和最新版本,它可以工作;
                    AppServiceProvider.php 只需 1 处更改

                    use Illuminate\Support\Facades\Schema;
                    
                    public function boot()
                    {
                      Schema::defaultStringLength(191);
                    }
                    

                    【讨论】:

                      【解决方案19】:

                      在其他 Anwser 中都有很好的描述 您可以在下面的链接中查看更多详细信息(使用键“索引长度和 MySQL / MariaDB”搜索) https://laravel.com/docs/5.5/migrations

                      但这不是这个答案的目的!即使做了上面的事情你会喜欢得到另一个错误(那是你喜欢启动php artisan migrate的时候命令,由于长度问题,操作像卡在中间。解决方法如下,用户表就像创建没有其余部分或不完全正确) 我们需要回滚k。默认回滚不会做。因为迁移的操作不喜欢完成。您需要手动删除数据库中新创建的表。

                      我们可以使用 tinker 来做到这一点,如下所示:

                      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
                      

                      【讨论】:

                        【解决方案20】:

                        设置数据库引擎 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();
                                });
                        

                        【讨论】:

                          【解决方案21】:

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

                          我是 Laravel 的新手,我没有复制“使用 Illuminate .....”,因为我真的没有注意,因为在功能启动的正上方你已经有一个 使用 声明。

                          希望对大家有所帮助

                          **use Illuminate\Support\Facades\Schema;**
                          
                          public function boot()
                          {
                              Schema::defaultStringLength(191);
                          }
                          

                          【讨论】:

                          • 你也可以在任何外观前面加上\
                          【解决方案22】:

                          对于 Laravel >= 5.6 用户

                          打开AppServiceProvider.php文件

                          使用下面的类

                          use Illuminate\Support\Facades\Schema;
                          

                          然后在boot方法里面添加下面一行

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

                          【讨论】:

                            【解决方案23】:

                            对于 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'
                            

                            【讨论】:

                              【解决方案24】:

                              如果您尝试了所有其他答案但都没有奏效,您可以从数据库中删除所有表,然后使用以下命令一次性执行迁移命令:

                              php artisan migrate:fresh
                              

                              【讨论】:

                                【解决方案25】:
                                File: config/database.php
                                change the following
                                FROM ->
                                'charset' => 'utf8mb4',
                                'collation' => 'utf8mb4_unicode_ci',
                                
                                TO ->
                                'charset' => 'utf8',
                                'collation' => 'utf8_unicode_ci',
                                

                                【讨论】:

                                • 虽然这可能会回答问题,但最好添加一些关于此答案如何有助于解决问题的描述。请阅读How do I write a good answer 了解更多信息。
                                【解决方案26】:

                                如果您看到此错误,那么您肯定需要在 AppServiceProvider.php 文件 -> 可以在 app-&gt;providers: 中找到

                                需要修改

                                use Illuminate\Support\Facades\Schema; //see if you have this class if not add it.
                                
                                public function boot()
                                {
                                    Schema::defaultStringLength(191); //make sure you add this line
                                }
                                

                                这应该可以解决您的问题,您可以查看有关此问题的 Laravel 新闻。 https://laravel-news.com/laravel-5-4-key-too-long-error

                                【讨论】:

                                  【解决方案27】:

                                  我有问题,改变'config/database'的配置

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

                                  在数据库中保持相同的模式。

                                  然后我下达了命令

                                  php artisan migrate
                                  

                                  【讨论】:

                                    【解决方案28】:

                                    请打开userpassword 其余文件。文件位于 database/migrations 文件夹中。

                                    添加一行

                                    Schema::defaultStringLength(191); in up function in both files.
                                    

                                    然后运行

                                    php artisan migrate
                                    

                                    【讨论】:

                                    • 对于任何使用 String 数据类型的模型,您都必须这样做,因此这不是最优的。其他答案针对所有迁移处理一次。 “真正/最佳”的解决方案取决于您的环境和需求。如果您必须使用较旧的 MySQL(或 Maria)但希望保持 250 字符串长度并且不需要表情符号,则切换 DB 字符集。否则缩短提供程序中的最大字符串长度。
                                    【解决方案29】:

                                    2016 年 10 月 24 日 Taylor Otwell 在 Twitter 上宣布 Laravel 的作者

                                    "utf8mb4" 将成为 Laravel 5.4 中默认的 MySQL 字符集,以提供更好的表情符号支持。 ?Taylor Otwell Twitter Post

                                    5.4 版之前的字符集是utf8

                                    在本世纪,许多网络应用程序包括聊天或某种平台以允许其用户交谈,并且许多人喜欢使用表情符号或笑脸。这是一些需要存储更多空间的超级字符,只有使用utf8mb4 作为字符集才有可能。这就是他们迁移到utf8mb4 只是为了空间目的的原因。

                                    如果您在Illuminate\Database\Schema\Builder 类中查找,您将看到$defaultStringLength 设置为255,并且要修改它,您可以通过Schema 外观并调用@ 987654323@ 方法并传递新的长度。

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

                                    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

                                    您可以在此处了解更多信息 The utf8mb4 Character Set (4-Byte UTF-8 Unicode Encoding) Limits on Table Column Count and Row Size

                                    【讨论】:

                                    • 这是解释191 幻数的唯一答案。
                                    【解决方案30】:

                                    如果有人在这样做后仍遇到此问题,则上述更改。例如,在我的情况下,我做了以下更改,

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

                                    但由于两个原因,它不会立即起作用。一个是如果你使用的是 lumen 而不是 laravel,你可能必须先在 app.php 文件中取消注释这一行。

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

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

                                    php artisan make:migration <your_table_name>
                                    

                                    因为现在只有您对 ServiceProvider 所做的更改才会起作用。

                                    【讨论】:

                                      猜你喜欢
                                      • 1970-01-01
                                      • 2019-02-14
                                      • 2019-05-17
                                      • 2015-04-22
                                      • 2021-02-08
                                      • 2015-07-22
                                      • 2016-06-19
                                      • 2018-01-28
                                      • 1970-01-01
                                      相关资源
                                      最近更新 更多