【问题标题】:Foreign key constraint fails in transaction外键约束在事务中失败
【发布时间】:2012-07-11 13:16:29
【问题描述】:

我正在使用 PHP/MySQL + Yii 框架开发一个基于 Web 的应用程序。该问题是事务中的约束检查错误。

我有以下表格:

用户

CREATE TABLE IF NOT EXISTS `User` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(64) DEFAULT NULL,
  `surname` varchar(64) DEFAULT NULL,
  `email` varchar(128) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `creation_date` datetime DEFAULT NULL,
  `last_login_date` datetime DEFAULT NULL,
  `status` tinyint(1) DEFAULT '0',
  `level` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=40 ;

候选人信息

CREATE TABLE IF NOT EXISTS `CandidateInfo` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `candidate_status_id` int(11) DEFAULT NULL,
  `name` varchar(64) DEFAULT NULL,
  `surname` varchar(64) DEFAULT NULL,
  `email` varchar(128) DEFAULT NULL,
  `gender` tinyint(1) DEFAULT '0',
  `date_of_birth` datetime DEFAULT NULL,
  `home_phone` varchar(20) DEFAULT NULL,
  `mobile_phone` varchar(20) DEFAULT NULL,
  `creation_date` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `rating` tinyint(1) DEFAULT '0',
  `location` varchar(100)DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_candidateinfo_user` (`id`),
  KEY `FK_candidateinfo_candidatestatus` (`candidate_status_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=26 ;

基本上我正在尝试向 User 表添加新行,然后使用插入 ID 向 CandidateInfo 表(user_id 列)添加新行

php代码如下

$transaction = Yii::app()->db->beginTransaction();
try {
    $user->save();
    $candidate->setAttribute('user_id', $user->id);
    $candidate->save();
    $transaction->commit();
} catch (Exception $e) {
    $transaction->rollBack();
    var_dump($e->getMessage());
}

错误是:

 SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`origo`.`CandidateInfo`, CONSTRAINT `FK_candidateinfo_user` FOREIGN KEY (`id`) REFERENCES `User` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION). The SQL statement executed was: INSERT INTO `CandidateInfo` (`gender`, `rating`, `name`, `surname`, `email`, `date_of_birth`, `home_phone`, `mobile_phone`, `user_id`) VALUES (:yp0, :yp1, :yp2, :yp3, :yp4, :yp5, :yp6, :yp7, :yp8)

当我检查 mysql 查询日志时,我发现它为 CandidateInfo 表的 INSERT 语句采用了正确的 user_id。但因上述错误而失败。根据我的理解,它应该可以工作,但可能是我弄错了,这不是交易的工作方式。

两个表都是 InnoDB。

提前致谢。

编辑: 抱歉忘记粘贴 FK 关系。

ALTER TABLE `CandidateInfo`
  ADD CONSTRAINT `FK_candidateinfo_candidatestatus` FOREIGN KEY (`candidate_status_id`) REFERENCES `CandidateStatus` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  ADD CONSTRAINT `FK_candidateinfo_user` FOREIGN KEY (`id`) REFERENCES `User` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;

【问题讨论】:

  • 您的表样本都没有任何外键,而且您在候选信息中的 id 字段中有一个重复的键。仅仅命名一个键 FK_whatever 并不能使它成为一个外键 - 你只是有普通的键。
  • 显然忘记将它们包含在 DDL 中,抱歉。
  • 好的,你有两个键,看起来你正在设置 user_id 一个......那么你把候选状态的值放在哪里?
  • 这是一个默认为NULL的列。我没有在查询中为它设置任何值。

标签: php mysql transactions yii innodb


【解决方案1】:
ALTER TABLE `CandidateInfo`
  ADD CONSTRAINT `FK_candidateinfo_candidatestatus` FOREIGN KEY (`candidate_status_id`) REFERENCES `CandidateStatus` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  ADD CONSTRAINT `FK_candidateinfo_user` FOREIGN KEY (`id`) REFERENCES `User` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;

应该是

ALTER TABLE `CandidateInfo`
  ADD CONSTRAINT `FK_candidateinfo_candidatestatus` FOREIGN KEY (`candidate_status_id`) REFERENCES `CandidateStatus` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  ADD CONSTRAINT `FK_candidateinfo_user` FOREIGN KEY (`user_id`) REFERENCES `User` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;

你的 id 引用了 id。

【讨论】:

    【解决方案2】:

    你的错误堆栈:

    SQLSTATE[23000]:完整性约束违规:1452 无法添加或更新子行:外键约束失败(origo.CandidateInfo,CONSTRAINT FK_candidateinfo_user FOREIGN KEY(id)参考User (id) 删除时不执行更新不执行操作)。

    执行的SQL语句是:

    INSERT INTO `CandidateInfo`
    ( `gender`, `rating`, `name`, `surname`, `email`, 
      `date_of_birth`, `home_phone`, `mobile_phone`, `user_id`
    )
    VALUES ( :yp0, :yp1, :yp2, :yp3, :yp4, :yp5, :yp6, :yp7, :yp8 )
    

    您的CandidateInfo 表将id 字段定义为auto_increment 主键字段和外键。
    并且您的 insert 语句不包括 id,从其父 user 表中读取。
    因此在插入 new id 值时会为 candidateinfo 表生成并应用。
    哪个实习生失败了,因为它不匹配父表user 的任何主键id 值。

    因此是错误。

    注意
    在子表中,如果您将主控的 pk 字段作为外键字段,
    你不应该为它申请auto_increment,而只是参考。


    仔细观察candidateinfo 结构,我觉得您可能希望将use_id 映射到user.id 字段。使用正确的外键定义进行更改将解决您的问题。

    【讨论】:

    • 是的,我的错。显然我在编写表定义时忽略了。 user_id(不是id)列应该引用User表的id。
    猜你喜欢
    • 2013-05-29
    • 1970-01-01
    • 2013-03-04
    • 2016-08-17
    • 2011-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-23
    相关资源
    最近更新 更多