当检查为 0 时,啥会导致外键异常?

Posted

技术标签:

【中文标题】当检查为 0 时,啥会导致外键异常?【英文标题】:What can be causing a foreign key exception when check is on 0?当检查为 0 时,什么会导致外键异常? 【发布时间】:2020-11-08 22:17:42 【问题描述】:

我正在尝试修复我为 MineCraft 服务器制作的一个小插件。该插件使用尝试自动调整服务器需求的代码,首先转换旧表上的表,创建新表,然后使用一些包含人工决策的对象来解析或更新新表的特定信息,解析所有数据尚未复制到新表中,然后删除旧表。

代码有点乱,这几天我没有太多时间,但我试图获得一周的空闲时间来重新制作插件的所有代码。问题是一切正常,但有一天我决定更新我用于测试的服务器上的插件,即使用 mysql。这个服务器的问题是我一直在使用相同的代码,我没有遇到问题,但是一段时间没有使用它,现在它不能工作了。

这是失败的代码部分:

    protected boolean tables() 
        boolean update = false, result = update;
        if (!this.sql.execute(
                "CREATE TABLE IF NOT EXISTS information(param VARCHAR(16),value VARCHAR(16),CONSTRAINT PK_information PRIMARY KEY (param));",
                new Data[0]))
            return false;
        List<String> tlist = new ArrayList<>();
        try 
            this.sql.execute("SET FOREIGN_KEY_CHECKS=0;", new Data[0]);
            ResultSet set = this.sql.query("SELECT value FROM information WHERE `param`='version';", new Data[0]);
            String version = "";
            if (set.next())
                version = set.getString(1);
            if (!version.equals(MMOHorsesMain.getPlugin().getDescription().getVersion())) 
                update = true;
                ResultSet tables = this.sql.query("SHOW TABLES;", new Data[0]);
                while (tables.next()) 
                    String name = tables.getString(1);
                    if (!name.equals("information")) 
                        if (!this.sql.execute("CREATE TABLE " + name + "_old LIKE " + name + ";", new Data[0]))
                            throw new Exception();
                        if (!this.sql.execute("INSERT INTO " + name + "_old SELECT * FROM " + name + ";", new Data[0]))
                            throw new Exception();
                        tlist.add(name);
                    
                
                String remove = "";
                for (String table : tlist)
                    remove = String.valueOf(remove) + (remove.isEmpty() ? "" : ",") + table;
                this.sql.reconnect();
                this.sql.execute("DROP TABLE IF EXISTS " + remove + ";", new Data[0]);

数据库存储了一个额外的数据,它是插件的版本。我用它来检查数据库是否来自另一个版本,如果是这样,则重新生成数据库。它在 SQLite 上运行良好,但唯一的问题出现在 MySQL 上。

第一部分获取实际版本并进行检查。该插件开始禁用外键。这不是最好的部分,但正如我所说,我实际上并没有时间重新制作所有这些代码,而且由于一些 GitHub 问题,我丢失了最后更新的一部分,因此这些代码来自编译版本。如果它需要更新,它会开始转换 _old 表上的每个表。这里一切正常,数据被解析到 _old 表并得到正确管理,但问题是何时必须删除原始表。

DROP TABLE IF EXISTS cosmetics,horses,inventories,items,trust,upgrades;

这是用于删除原始表的SQL语句,但是,我不知道它是否像那样工作,但如果是这样的话,_old表也得到了原始表的外键,什么时候我尝试删除它们,它不允许,即使 FOREIGN_KEY_CHECKS 为 0。我还在之前设置了一个调试,以检查检查是否被禁用,并且它是。为了模拟人们习惯工作的最佳环境,我正在使用来自朋友的 prebuilder minecraft 托管,使用 MariaDB 10.4.12。

我问他自从我上次准备服务器后是否更新了它,但我仍在等待他的回答。无论如何,即使它是新的或旧的 MariaDB 版本,我正在尝试使其尽可能具有弹性,以便它可以毫无问题地适应不同的版本。一切似乎都正常,但由于我无法删除原始数据库,因此无法将它们替换为新格式。

我希望这只是某些数据库配置发生的错误,但我想得到有知识的人的回答,以确保我没有上传损坏的版本。

【问题讨论】:

",它不允许,"-- 这是什么意思?您是否尝试过在 MySQLWorkbench 中调试查询? 我必须尝试,但我需要复制我正在使用的语句。使用“它不允许”,我的意思是它不允许我删除表,因为会引发 MySQLIntegrityConstraintViolationException。 “我必须尝试,但我需要复制我正在使用的语句”——设置断点并捕获提交给驱动程序的 SQL。然后将其粘贴到 MySQLWorkbench。 可能是会话问题? ***.com/questions/8538636/… 我有代码上的句子和 MariaBD 服务器上的表名。我执行了所有句子并且没有给出 MySQL Workbench 的问题,似乎是在 Java 上。无论如何,我会尽量确保这是相同的句子。 【参考方案1】:

谢谢nicomp,回答是保持相同的会话。我的重新连接方法不是很灵活,因为我来自一些奇怪的高延迟经历,比如 1 秒的会话,因为它很容易断开连接,并且错误地检测到连接,因此它正在重新连接并删除会话的配置.

【讨论】:

以上是关于当检查为 0 时,啥会导致外键异常?的主要内容,如果未能解决你的问题,请参考以下文章

主键约束,外键约束,空值约束,默认值约束,唯一约束,检查约束的各个作用是啥?

由于试图创建表的外键约束导致的 SQL 异常

Django:如何将外键检查设置为 0

如何永久禁止外键检查

小议Oracle外键约束修改行为(一)

mysql 删除表 外键出错