MySQL InnoDB表之间的外键不起作用......为什么?

时间:2012-01-22 10:22:57

标签: mysql foreign-keys

我有以下表格:

物种(MyIsam)
image(InnoDB)
specie_map(InnoDB)

specie_map表应该将图像映射到一个物种,因此具有以下列:

specie_id
image_id

两者都是int 11,就像specie和image表的id列一样。我知道我无法在specie_id和specie => id之间创建外键,因为specie表是MyIsam表。但是,我希望可以在image_id和image => id之间创建一个外键。

我可以创建该外键并保存它,但是,我与之关联的CASCADE操作不起作用。删除图像时,它不会删除与其关联的specie_map条目。我希望这可以工作,因为这个外键是在InnoDB表之间。这两列都是索引的,并且具有相同的数据类型。

这是MySQL的限制,还是我做错了什么?

更新:根据要求提供表格定义。我剪掉了不重要的专栏:

-- ----------------------------
-- Table structure for `image`
-- ----------------------------
DROP TABLE IF EXISTS `image`;
CREATE TABLE `image` (
  `id` int(11) NOT NULL auto_increment,
  `guid` char(36) default NULL,
  `title` varchar(255) NOT NULL,
  `description` text,
  `user_id` int(11) NOT NULL,
  `item_id` int(11) default NULL,
  `date_uploaded` timestamp NOT NULL default '0000-00-00 00:00:00',
  `date_created` timestamp NOT NULL default '0000-00-00 00:00:00',
  `date_modified` timestamp NOT NULL default '0000-00-00 00:00:00',
  `status` enum('softdeleted','tobedeleted','active') default 'active',

  PRIMARY KEY  (`id`),
  KEY `image_user` (`user_id`),
  KEY `image_item` (`item_id`),
  KEY `image_mod_by` (`moderated_by`),
  CONSTRAINT `image_mod_by` FOREIGN KEY (`moderated_by`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `image_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='stores image data (not file data)';


-- ----------------------------
-- Table structure for `specie`
-- ----------------------------
DROP TABLE IF EXISTS `specie`;
CREATE TABLE `specie` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(256) NOT NULL,
  `commonname` varchar(256) NOT NULL,
   PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=22 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;


-- ----------------------------
-- Table structure for `specie_map`
-- ----------------------------
DROP TABLE IF EXISTS `specie_map`;
CREATE TABLE `specie_map` (
  `id` int(11) NOT NULL auto_increment,
  `image_id` int(11) NOT NULL,
  `specie_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `karma` int(11) NOT NULL,
  `date_created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`id`),
  KEY `image_id` (`image_id`),
  KEY `specie_id` (`specie_id`),
  CONSTRAINT `specie_map_ibfk_1` FOREIGN KEY (`image_id`) REFERENCES `image` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2 个答案:

答案 0 :(得分:2)

外键仅适用于mysql中的InnoDbMyISAM不支持它们(语句被忽略)。

你有没有理由混合使用多个数据库引擎?

答案 1 :(得分:2)

我认为您应该发布在尝试创建这些表和外键时使用的确切DDL语句。 innodb表之间的外键工作正常,但仍有一些需要注意的事项:

0)两个表都必须是InnoDB。其他海报已经突出了这一点,这可能是你问题的直接原因。

1)引用列(构成外键的列)的数据类型及其各自的引用列应该相同。例如,您无法在INT UNSIGNED列上创建外键约束到普通INT列。

2)如果外键是作为表DDL的一部分创建的,请确保将外键定义放在约束部分中,即在所有列定义下面。例如:

CREATE TABLE parent (
    id int unsigned PRIMARY KEY
);

CREATE TABLE child (
    parent_id int unsigned
,   foreign key (parent_id) 
        references parent (id)
);

会起作用但是:

CREATE TABLE child (
    parent_id int unsigned 
        foreign key references parent (id)
);

不会。它将无声地失败,因为即使在InnoDB创建表之前,MySQL的解析器也会忽略这些类型的约束定义(愚蠢,但就是这样)

3)所有引用列必须有索引。通常,引用的列将一起构成主键或唯一约束,但在定义外键之前定义此是您的职责。

最后的建议:如果您认为您的DDL没问题但执行时仍然出错,例如:

ERROR 1005 (HY000): Can't create table 'test.child' (errno: 150)
Warning (Code 150): Create table 'test/child' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns.

Error (Code 1005): Can't create table 'test.child' (errno: 150)

然后这些错误可能仍然没有揭示错误的真实性质(再次愚蠢,但就是这样)。为了更好地了解它,请在尝试创建外键后立即运行此命令:

SHOW ENGINE INNODB STATUS;

这将为您提供一堆状态信息,其中一个部分如下所示:

------------------------
LATEST FOREIGN KEY ERROR
------------------------
120122 11:38:28 Error in foreign key constraint of table test/child:
foreign key (parent_id) references parent (id) ):
Cannot find an index in the referenced table where the
referenced columns appear as the first columns, or column types
in the table and the referenced table do not match for constraint.
Note that the internal storage type of ENUM and SET changed in
tables created with >= InnoDB-4.1.12, and such columns in old tables
cannot be referenced by such columns in new tables.
See http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html
for correct foreign key definition.

正如您所看到的,这提供了更多信息并揭示了真正的问题,即“表中的列类型和引用的表与约束不匹配”

所以,请发布你的实际DDL,我确定那里有一个问题。