【问题标题】:MySQL DB is ignoring foreign key constraintsMySQL DB 忽略外键约束
【发布时间】:2017-11-17 02:47:00
【问题描述】:

我遇到了一个非常奇怪(也很可怕)的问题:MySQL DB 通常忽略外键约束!

我所有的表都是InnoDB,我正在用这样的 liquibase 创建它们:

<addForeignKeyConstraint baseColumnNames="user_account_id"
    baseTableName="account_transaction"
    constraintName="fk_account_transaction_user_account_id"
    referencedColumnNames="id"
    referencedTableName="user_account"/>

外键创建良好。在 HeidiSQL 中,我看到它们是这样的:

我还检查了 FOREIGN_KEY_CHECKS 并将其设置为 1 (SET FOREIGN_KEY_CHECKS=1;)

我所有的 ID 列都有BIGINT 的数据类型(不知道是否重要)。

还有一点值得一提:下面的陈述

  SELECT * FROM information_schema.TABLE_CONSTRAINTS
WHERE CONSTRAINT_SCHEMA = DATABASE();

返回一堆约束,但没有外键约束...当我在本地 mySQL DB 上执行相同的语句时,它返回所有约束,包括外键约束。我不知道它们之间有什么区别......

非常感谢任何帮助:)

@更新: 因此,MyISAM 和 InnoDB 的提示起到了作用。我之前确实调查过。但是,由于某种原因,我的表是 InnoDB,但我的数据库是 MyISAM。我将对此进行进一步调查:)

【问题讨论】:

  • 表是否使用了 MyISAM 存储引擎?您必须使用 InnoDB。外键约束在其他存储引擎中被忽略。 SELECT TABLE_NAME, ENGINE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE();
  • 不幸的是,正如我上面提到的,它们都是 InnoDB
  • 如果 FOREIGN KEY 约束未显示在 information_schema.table_constraints 中,则它们未定义。做一个SHOW CREATE TABLE account_transaction 来确认。 (最有可能的解释是存储引擎不是 InnoDB - 请检查 Bill Karwin 建议的 information_schema.tables 的 ENGINE 列。我认为 HeidiSQL 显示的是索引,而不是约束。听起来 Liquibase 正在阻碍更多比它有帮助。)
  • 另一种可能性是尚未针对此架构运行 Liquibase 更改。
  • 嗨。请阅读minimal reproducible example 并采取行动。 PS 事实证明,它有助于调试,因为“mySQL DB 通常忽略外键约束!”而是“几乎可以肯定我在推理和/或解释中犯了另一个错误”。例如,情况并不“奇怪”,它一直在发生;这就是SO存在的原因。我会把“吓人”当成诗意;但除了你的编程方法之外,我仍然不太可能谈论任何事情。

标签: mysql foreign-keys


【解决方案1】:

正如 Bill Karwin 在他的评论中指出的那样,如果表不是 InnoDB,则 FOREIGN KEY 约束将被忽略。

演示:

CREATE TABLE foo_p
( id BIGINT UNSIGNED PRIMARY KEY
) ENGINE=MYISAM
;  

CREATE TABLE foo_c
( id   BIGINT UNSIGNED PRIMARY KEY
, p_id BIGINT UNSIGNED
) ENGINE=MYISAM
;

添加外键约束:

ALTER TABLE foo_c 
  ADD CONSTRAINT fk_foo_c_foo_p
  FOREIGN KEY (id) REFERENCES foo_p (id)
  ON DELETE NO ACTION ON UPDATE NO ACTION
;  

MySQL 创建一个索引,但不是一个外键。

将存储引擎更改为 InnoDB 不会创建外键:

ALTER TABLE foo_p ENGINE=INNODB ;

ALTER TABLE foo_c ENGINE=INNODB ;

使用SHOW CREATE TABLE foo_c查看表定义:

CREATE TABLE `foo_c` (
  `id` BIGINT(20) UNSIGNED NOT NULL,
  `p_id` BIGINT(20) UNSIGNED DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_foo_c_foo_p` (`id`)
) ENGINE=INNODB

有一个索引(从 MyISAM 定义转换而来)但没有外键。

添加外键:

ALTER TABLE foo_c 
  DROP KEY fk_foo_c_foo_p  
, ADD CONSTRAINT fk_foo_c_foo_p
  FOREIGN KEY (p_id) REFERENCES foo_p (id)
  ON DELETE NO ACTION ON UPDATE NO ACTION
;

SHOW CREATE TABLE 显示 FOREIGN KEY 约束,以及自动创建的索引:

CREATE TABLE `foo_c` (
  `id` BIGINT(20) UNSIGNED NOT NULL,
  `p_id` BIGINT(20) UNSIGNED DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_foo_c_foo_p` (`p_id`),
  CONSTRAINT `fk_foo_c_foo_p` FOREIGN KEY (`p_id`) REFERENCES `foo_p` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=INNODB

【讨论】:

  • 哇,这太有道理了!非常感谢您分享您的知识:)
猜你喜欢
  • 2011-05-15
  • 1970-01-01
  • 2012-04-12
  • 2021-04-02
  • 1970-01-01
  • 1970-01-01
  • 2017-04-21
  • 2019-08-06
  • 1970-01-01
相关资源
最近更新 更多