无法在没有主键的情况下创建或更改 table - Laravel DigitalOcean 托管数据库

Unable to create or change a table without a primary key - Laravel DigitalOcean Managed Database

我刚刚使用(托管数据库)将我的应用程序部署到 DigitalOcean,调用 php artisan migrate

时出现以下错误

SQLSTATE[HY000]: General error: 3750 Unable to create or change a table without a primary key, when the system variable 'sql_require_primary_key' is set. Add a primary key to the table or unset this variable to avoid this message. Note that tables without a primary key can cause performance problems in row-based replication, so please consult your DBA before changing this setting. (SQL: create table `sessions` (`id` varchar(255) not null, `user_id` bigint unsigned null, `ip_address` varchar(45) null, `user_agent` text null, `payload` text not null, `last_activity` int not null) default character set utf8mb4 collate 'utf8mb4_unicode_ci')

当 mysql var sql_require_primary_key 设置为 true 时,Laravel 迁移似乎不起作用。

你有什么解决办法吗?

启用后,sql_require_primary_key 具有以下效果:

  1. 尝试创建没有主键的新 table 失败并出现错误。这包括 CREATE TABLE ... LIKE。它还包括 CREATE TABLE ... SELECT,除非 CREATE TABLE 部分包含主键定义。
  2. 尝试从现有 table 中删除主键失败并出现错误,但允许删除主键并在同一 ALTER TABLE 语句中添加主键。

即使 table 也包含 UNIQUE NOT NULL 索引,删除主键也会失败。

  1. 尝试导入没有主键的 table 失败并出现错误。

默认值为 OFF ,但在您的情况下,您需要从 ON

设置 OFF

IMPORTANT LINK

HOW TO SET

根据 MySQL 文档,此系统变量的用途是

to avoid replication performance issues: "Enabling this variable helps avoid performance problems in row-based replication that can occur when tables have no primary key."

恕我直言,您的问题有两种可能的选择;

  • 将主键添加到这个和迁移中的每个 table,包括临时的 table。这个更好,我认为这样做更方便,因为每个 table.
  • 都有主键没有缺点

Whether statements that create new tables or alter the structure of existing tables enforce the requirement that tables have a primary key.

  • 更改您的提供商,因为根据 here "We support only MySQL v8."

这里还有bug report

只需添加 set sql_require_primary_key = off 像这样

到您的 SQL 文件。

将此行添加到您的迁移文件中。 $table->增量('aid');

很遗憾,我们无法更改数字海洋 MySQL 数据库中的 sql_require_primary_key 值。相反,您可以通过添加 primary()

将 id 设置为主键

我试图通过使用 WordPress 安装中的 mysqldump 文件导入 DO Managed MySQL 来解决这个问题。我发现将它添加到文件顶部确实对我的导入有用。

SET @ORIG_SQL_REQUIRE_PRIMARY_KEY = @@SQL_REQUIRE_PRIMARY_KEY;
SET SQL_REQUIRE_PRIMARY_KEY = 0;

然后我使用 JetBrains DataGrip 进行了导入,并且没有出现错误。

在您的第一次迁移中添加:

\Illuminate\Support\Facades\DB::statement('SET SESSION sql_require_primary_key=0');

内部:Schema::create() 函数。

我通过工单联系了 DigitalOcean,询问他们是否想禁用该要求,他们在第二天就这样做了:)

所以你可以直接问他们

Thanks for getting in touch with us! I understand you will like to disable the primary requirement on your managed database. The primary requirement for your managed database ****** has been disabled

定义了一个简洁的解决方案here。解决方案是添加监听器来迁移脚本,并在执行迁移之前和之后打开和关闭 sql_require_primary_key。此解决方案解决了无法修改迁移脚本的问题,例如当它们来自库或 Voyager 等框架时。

<?php

namespace App\Providers;

    use Illuminate\Database\Events\MigrationsStarted;
    use Illuminate\Database\Events\MigrationsEnded;
    use Illuminate\Support\Facades\DB;
    use Illuminate\Support\Facades\Event;
    use Illuminate\Support\ServiceProvider;
    
    class AppServiceProvider extends ServiceProvider {
        /**
         * Register any application services.
         *
         * @return void
         */
        public function register() {
    
            // check this one here https://github.com/laravel/framework/issues/33238#issuecomment-897063577
            Event::listen(MigrationsStarted::class, function (){
                if (config('databases.allow_disabled_pk')) {
                    DB::statement('SET SESSION sql_require_primary_key=0');
                }
            });
    
            Event::listen(MigrationsEnded::class, function (){
                if (config('databases.allow_disabled_pk')) {
                    DB::statement('SET SESSION sql_require_primary_key=1');
                }
            });
        } 
// rest of the class 

}

对于更大的 sql 文件,可以使用此命令(如果您的文件大小 <8GB,nano 编辑器可以在 1 周内打开,哈哈):

第一个:

sed  -i '1i SET SQL_REQUIRE_PRIMARY_KEY = 0;' db.sql

第二个:

sed  -i '1i SET @ORIG_SQL_REQUIRE_PRIMARY_KEY = @@SQL_REQUIRE_PRIMARY_KEY;' db.sql

从 2022 年 3 月开始,您现在可以通过向数字海洋 API 发出请求来配置您的 MYSQL 和其他数据库。 这是参考:https://docs.digitalocean.com/products/databases/mysql/#4-march-2022

解决问题的步骤:

步骤 - 1:创建 AUTH 令牌以访问数字海洋 APIs。 https://cloud.digitalocean.com/account/api/tokens

STEP - 2:通过使用您刚刚在上面生成的承载令牌向下面URL发送GET请求来获取数据库集群ID。

URL: https://api.digitalocean.com/v2/databases

步骤 - 3:使用 PATCH 请求以及承载令牌和有效负载点击下面的 URL。

URL: https://api.digitalocean.com/v2/databases/{YOUR_DATABASE_CLUSER_ID}/config

有效载荷:{“配置”:{“sql_require_primary_key”:假}}

就是这样。它运行完美。

更多信息,请参考API文档: https://docs.digitalocean.com/products/databases/mysql/#latest-updates