ChatGPT解决这个技术问题 Extra ChatGPT

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

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

[Illuminate\Database\QueryException] SQLSTATE[42000]:语法错误或访问冲突:1071 指定的键太长;最大密钥长度为 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');
});

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

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

z
zeros-and-ones

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

$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 < 85 ( 1 字节 ) = O(85) 或 utf8_general_ci 用于 VARCHAR(X) 且 X >= 86 ( 2 bytes ) -> 767 / 2 = 383。还要考虑多列索引中的其他列长度。
您可能还想直接编辑迁移文件中特定列的长度,而不是为所有字符串列指定默认长度,因为并非所有列都需要此约束,因为它们不在任何索引中。 $table->string('column_name',191);
s
scorer

更新 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.cnf 配置文件(当前所有新安装都使用 utf8mb4)。
或者 - 添加另一个字段,计算电子邮件的哈希值,使字段唯一,永远解决问题,避免摆弄数据库初始化变量。
如果有人使用 Doctrine 2,您可以通过将 options={"row_format"="DYNAMIC"} 传递给您的 @Table 注释来设置 ROW_FORMAT。
v
varta

如果您正在使用或更新到 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 进行解释。但仍然是一个方便的修复。
B
Brendan

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

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

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

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


u
user3278647

这对我有用:

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


这对我有用。我使用服务器版本:10.1.22-MariaDB - 源代码分发
A
Avijit Mandal

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

R
Ramv V

从 charset 中删除 mb4 并从 config/database.php 中删除 collation,然后它将成功执行。 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci',


V
Vanndy

对于 laravel 5.4,只需编辑文件

App\Providers\AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

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

M
Muthu17

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

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

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

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

谢谢


以前的答案都不适合我,但这个答案就像一个魅力!这很有意义,我相信以前版本的 Laravel DB 引擎默认设置为 InnoDB,所以我们之前没有遇到这些错误。
是的,需要做一些其他的答案,这也是。
A
Adrian

在文件 config/database.php 中:

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

将此行更改为:

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

F
Faizan Noor
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 了解更多信息。
F
Farhan Yudhi Fatah

转到您的 config/database.php 并将字符集和排序规则从 utf8mb4 更改为 utf8

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

我的问题用这种方法解决了,祝你好运!


d
dilantha111

如果有人即使在这样做之后也遇到了这个问题,上面提到的变化。例如,就我而言,我做了以下更改,

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 所做的更改才会起作用。


W
Wael Assaf

对于 Laravel >= 5.6 用户

打开 AppServiceProvider.php 文件

使用以下类

use Illuminate\Support\Facades\Schema;

然后在 boot 方法中添加以下行

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

M
Manoj Thapliyal

我添加到迁移本身

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

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


a
ahmed farghaly

对于 laravel 5.7,在 appserviceprovider.php 中编写这些代码

  use Illuminate\Support\Facades\Schema;

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

D
David Buck

您可以转到 app/Providers/AppServiceProvider.php 并将其导入

use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;

也在引导功能中添加这个

Schema::defaultStringLength(191);

对我的情况没有帮助。
C
Chetan Godhani

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

排序规则到“utf8mb4_unicode_ci”到“utf8_unicode_ci”

在 config/database.php 文件中

它对我有用。


A
Ali Turki

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


谢谢,为我工作。 mamp mysql 与 laravel 5.6.23
I
Irteza Asad

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

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

use Illuminate\Support\Facades\Schema;

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

你应该很高兴。


T
Thomas Fritsch

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

use Illuminate\Support\Facades\Schema;

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

Y
Yves Kipondo

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

“utf8mb4” 将成为 Laravel 5.4 中的默认 MySQL 字符集,以提供更好的表情符号支持。 🙌 Taylor Otwell Twitter 帖子

在 5.4 版之前,字符集是 utf8

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

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

在 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 幻数的唯一答案。
K
Khn Rzk

编辑 config 文件夹中的 database.php 文件。从

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

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

它应该工作!


S
Samuel Aiala Ferreira

我想指出我错过的一些东西......

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

希望对任何人都有帮助

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

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

您也可以在任何外观前面加上 \
E
Emerson Santana Cunha

我有一个问题,更改“配置/数据库”的配置

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

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

然后我下达了命令

php artisan migrate

N
Naveen Kumar V

解决方案:

首先将app\Providers\AppServiceProvider.php中的defaultStringLength改为191:

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

然后,在 config\database.php 中按如下方式更改 charset and collation 值:

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

(link to know about MariaDB charset)


R
Richard Dawson

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

要使用 Brew 在您的 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(滚动细化为:迁移默认字符串长度


k
kroko

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

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


M
Mohamed Allal

所有在其他 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