无法在Laravel DigitalOcean管理的数据库中创建或更改没有主键的表

40

我刚刚使用(托管数据库)将我的应用部署到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变量sql_require_primary_key设置为true时,Laravel迁移不起作用。

您有任何解决方案吗?

14个回答

81

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

解决问题的步骤:

步骤1:创建用于访问数字海洋API的AUTH令牌。https://cloud.digitalocean.com/account/api/tokens

步骤2:使用刚刚生成的bearer token发送GET请求到以下URL以获取数据库集群ID。

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

步骤3:使用bearer token和有效载荷向下面的URL发送PATCH请求。

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

有效载荷:{"config": { "sql_require_primary_key": false }}

就这些。它完美无缺地工作了。

有关更多信息,请参考API文档:

https://docs.digitalocean.com/products/databases/mysql/#latest-updates 该链接为数字海洋(DigitalOcean)的MySQL数据库产品最新更新文档。

非常感谢,真的在 Digital Ocean API 上为我节省了很多压力。 - Arinzehills
4
对我很有用!如果您没有安装Postman,请使用此在线POST请求生成器https://reqbin.com/。 - Anand Singh
谢谢!你的回复是目前最好的解决方案。 - María Paulina
当通过Postman发送补丁请求时,如果您通过“原始”选项将正文/有效载荷发送,则最容易。感谢@hamzaajaz,节省了几个小时;)! - Fabus
尝试运行迁移以设置Pterodactyl时,遇到了这个确切的问题。你的解决方案在2023年仍然有效! - undefined
显示剩余9条评论

38

我试图通过将来自WordPress安装的mysqldump文件导入到DO Managed MySQL中来解决这个问题。我发现在文件顶部添加以下内容确实适用于我的导入。

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

然后我使用JetBrains DataGrip导入,而且没有错误。


2
为什么在导入之前缺少主键的表中不添加主键呢? - darryn.ten
请注意,根据DigitalOcean的说法,“包含没有主键且包含超过5000行的表的MySQL数据库可能会遇到复制问题。” - Liam
如果您在2022年或之后看到此内容,此答案是您要寻找的,因为它不需要操纵您的mysqldump文件。 - Zach Gollwitzer
我仍然更喜欢这个解决方案,而不是选择的答案。@darryn.ten 有时候,这可能并不是必需的。有些人只是想看着世界燃烧。 - undefined

21

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

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

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


这解决了会话特定情况的问题。 - Qumber
1
你提到了 Schema::create() 函数,但是该函数需要两个参数。我想你是想在 Schema::Create() 之前放置这行代码,对吗? - lsimonetti
是的,lsimonetti你说得对。 - Usman Ayub

17

只需添加 set sql_require_primary_key = off 就像这样

点击查看图像

到你的SQL文件中。


7
关闭SQL的主键限制。 - Namal
1
在DigitalOcean托管的数据库中,这是不允许的。 - Peter Fox
仅供参考,您可以在Digital Ocean托管的数据库上将sql_require_primary_key设置为关闭(将其设置为0)。默认值始终为开启,但您可以为任何会话重置它。在您的表上包含主键始终是最简单的方法,否则可以将用于设置此变量的原始SQL添加到需要它的Laravel迁移脚本中。 - Jason

12

这里定义了一个聪明的解决方案,点此查看。解决方案是在执行迁移之前和之后添加侦听器以打开和关闭 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 

}

1
对我来说就像魔法一样有效。 - stanley mbote
这适用于 Laravel 10 和 DigitalOcean。 - Ntiyiso Rikhotso

7

对于较大的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

5

我通过一张工单联系了DigitalOcean,询问他们是否可以取消要求,第二天他们就做到了 :)

所以你可以直接向他们提出请求

感谢您与我们联系! 我理解您想要在您的托管数据库上禁用主要要求。Your managed database ****** 的主要要求已被禁用。


是的,但请注意,“包含没有主键且包含超过5000行的MySQL数据库可能会遇到复制问题。” - Liam

5
根据MySQL文档,此系统变量的目的是为了避免复制性能问题:“启用此变量有助于避免基于行的复制中可能出现的表没有主键时的性能问题。”在我看来,您的问题有两个可能的选择:将主键添加到此迁移中的每个表中,包括临时表。这是更好的、更方便的方法,因为对于每个表都有主键没有缺点。无论是创建新表还是修改现有表的结构的语句都要求表具有主键。或者更改您的提供商,因为根据这里的说法,“我们仅支持MySQL v8”。此外,这里是一个错误报告。

3

很遗憾,在Digital Ocean MySQL数据库中,我们无法更改sql_require_primary_key的值。不过,您只需通过添加primary()将id设置为主键即可。


1
我把它添加到了 DigitalOcean 上的 SQL 文件中,然后它就正常工作了。 - Aryeh Armon

2
启用sql_require_primary_key后,会产生以下影响:
  1. 尝试创建一个没有主键的新表将失败,并返回错误。包括使用 CREATE TABLE ... LIKE 创建和使用 CREATE TABLE ... SELECT 创建(除非 CREATE TABLE 部分包含主键定义)。
  2. 尝试从现有表中删除主键将失败,并返回错误,但在同一 ALTER TABLE 语句中删除主键并添加主键是允许的。

即使表中也包含 UNIQUE NOT NULL 索引,删除主键仍将失败。

  1. 尝试导入没有主键的表将失败,并返回错误。

默认值为 OFF ,但在您的情况下,您需要将其设置为从 ONOFF

重要链接

如何设置


@Michal,您是否觉得这个答案有帮助?如果是,请标记为答案或点赞。 - Md. Amirozzaman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接