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

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

近期在 Laravel 项目中使用 MySQL 数据迁移时,遇到了一个让人困惑的问题:即使在迁移中显式指定了唯一键的长度,MySQL 仍然会报告唯一键太长的错误。

阅读更多:MySQL 教程

问题描述

在进行 Laravel 数据迁移时,代码类似如下:

public function up()
{
    Schema::table('users', function (Blueprint table) {table->string('name')->unique();
    });
}

如上代码所示,创建了 users 数据表,并为 name 字段添加了唯一键约束。然而,执行 php artisan migrate 命令时,在 MySQL 中报错:

Specified key was too long; max key length is 1000 bytes (SQL: alter table `users` add unique `users_name_unique`(`name`))

但是,字符数并没有超限。于是,首先解决问题需要先了解唯一键的长度限制和字符集的关系。

字符集与唯一键长度限制

MySQL 数据库为了节省存储空间,采用了可变长度的字符编码,例如 utf8mb4。在 utf8mb4 编码下,每个字符最多占用 4 个字节,因此唯一键的长度限制是以字节为单位的。MySQL 在执行添加索引语句时,会将整个唯一键的字符串按照字节长度计算,若长度超过限制,则会报错。根据 MySQL 的文档,InnoDB 存储引擎中,唯一键的最大长度为 3072 字节,即字符数为 766。

但是,在 Laravel 5.8 中,string() 方法默认使用的是长度为 255 的 varchar 类型,所以当 key 的字符串长度超过 1000 时,MySQL 报错。

解决方法

一种解决方法是在每次创建数据表字段时,显式地指定该字段的长度和字符集。例如:

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

在字符集为 utf8mb4 的情况下,长度为 191 的字符数最多为 47,符合唯一键长度的限制。

另一种更为简单的方法是,在 AppServiceProvider.php 中,为所有默认的字符串长度设置成 191:

use Illuminate\Support\Facades\Schema;

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

这样,在使用 string() 方法创建新字段时,可以省略长度参数。如下:

$table->string('name')->unique();

这样创建的唯一键长度就会自动被限制在 191。

总结

Laravel 5.8 版本中默认使用的是 varchar(255) 字符串,当 MySQL 字符集采用 utf8mb4 编码时,每个字符会占用 4 个字节,且唯一键长度的限制是字节长度,因此当唯一键所对应字符串的长度超过 1000 时,MySQL 会报错。为此,在迁移时应特别关注唯一键的限制,采用上述两种方法之一即可解决问题。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程