MYSQL死锁(insert&update)

错误信息
exception 'CDbException' with message 'CDbCommand failed to execute the SQL statement: SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction' in /var/www/monitor/dev/yii/framework/db/CDbCommand.php:354
Stack trace:
#0 /var/www/monitor/dev/protected/commands/cron/Comment2AttrIdCommand.php(272): CDbCommand->execute()
#1 /var/www/monitor/dev/protected/commands/cron/Comment2AttrIdCommand.php(17): Comment2AttrIdCommand->findAttrId()
#2 /var/www/monitor/dev/yii/framework/console/CConsoleCommandRunner.php(65): Comment2AttrIdCommand->run(Array)
#3 /var/www/monitor/dev/yii/framework/console/CConsoleApplication.php(91): CConsoleCommandRunner->run(Array)
#4 /var/www/monitor/dev/yii/framework/base/CApplication.php(162): CConsoleApplication->processRequest()
#5 /var/www/monitor/dev/protected/commands/run_cron.php(17): CApplication->run()
问题代码A
$sql = "update comment2
    set attr_flag=101, attr_id=concat('2_', b2c_id), purchase_date={$date}
    where comment_time>={$db_indus->quoteValue($time_s)}
    and comment_time<{$db_indus->quoteValue($time_e)}
    and attr_flag=0
    and auction_sku=''";
$db_indus->createCommand($sql)->execute(); 
参考资料

http://www.cnblogs.com/crazylqy/p/7689447.html

初步结论

评论表的建表信息如下

CREATE TABLE `comment2` (
  `b2c` int(11) NOT NULL,
  `b2c_id` varchar(80) DEFAULT NULL,
  `b2c_shop_id` varchar(80) DEFAULT NULL,
  `comment_id` varchar(80) NOT NULL,
  `auction_sku` varchar(255) DEFAULT NULL,
  `comment_content` text,
  `comment_pics` text,
  `comment_time` datetime DEFAULT NULL,
  `position` text,
  `position_flag` tinyint(3) NOT NULL DEFAULT '0',
  `comment_nick` varchar(80) DEFAULT NULL,
  `tamllSweetLevel` tinyint(4) DEFAULT NULL,
  `tmallSweetPic` varchar(80) DEFAULT NULL,
  `reply_content` text,
  `append_comment_id` varchar(80) DEFAULT NULL,
  `append_comment_content` text,
  `append_comment_pics` text,
  `append_comment_time` datetime DEFAULT NULL,
  `append_reply_content` text,
  `reply_time` datetime DEFAULT NULL,
  `attr_id` varchar(255) NOT NULL DEFAULT '',
  `attr_flag` tinyint(3) NOT NULL DEFAULT '0' COMMENT'0:未处理;1:处理失败,solidify_item中无相应记录,使用父类ID;2:处理失败,超过14天直接使用父类ID;100:处理成功,子类;101:处理成功,父类',
  `purchase_date` int(8) NOT NULL DEFAULT '0' COMMENT '以solidify_item中<=评论日期的最晚记录的日期作为宝贝购买日期',
  `insert_date` int(8) NOT NULL DEFAULT '0',
  PRIMARY KEY (`comment_id`),
  KEY `idx_comment_time` (`comment_time`),
  KEY `idx_item` (`b2c_id`,`comment_time`),
  KEY `idx_insert_date` (`insert_date`,`b2c_id`,`comment_time`),
  KEY `idx_attr_flag` (`attr_flag`)
) ENGINE=TokuDB DEFAULT CHARSET=utf8
$sql = "insert into comment2 (b2c, insert_date, b2c_id, b2c_shop_id, comment_id, auction_sku, comment_content, comment_pics, comment_time, comment_nick, reply_content, append_comment_id, append_comment_content, append_comment_pics, append_reply_content, reply_time) values {$commentStr} 
on duplicate key update auction_sku = values(auction_sku), 
comment_content = values(comment_content), 
comment_pics = values(comment_pics), 
comment_nick = values(comment_nick), 
reply_content = values(reply_content), 
append_comment_content = values(append_comment_content), 
append_comment_pics = values(append_comment_pics), 
append_reply_content = values(append_reply_content)";

考虑代码A与评论爬虫脚本的以上代码B产生死锁;
A会给二级索引idx_comment_time和聚簇索引PRI的相关记录分别设排他锁,
B会在插入前申请插入意向锁,插入后给PRI的相关记录设共享锁,
由于加锁顺序不同,可能产生死锁。

修改如下
// 预处理----------------------------------------------------------------------------------------------------------------
while(1){
    $sql = "select comment_id 
        from comment2 
        where comment_time>={$db_indus->quoteValue($time_s)}
        and comment_time<{$db_indus->quoteValue($time_e)}
        and attr_flag=0
        limit {$limit}";
    $comment_ids = $db_indus->createCommand($sql)->queryColumn();
    if($comment_ids){
        $comment_ids_str = "'".implode("','", $comment_ids)."'";
        $sql = "update comment2 set attr_flag=9 where comment_id in ({$comment_ids_str})";
        $db_indus->createCommand($sql)->execute();
    }else{
        break;
    }
}
// 更新auction_sku=""
$sql = "update comment2
    set attr_flag=101, attr_id=concat('2_', b2c_id), purchase_date={$date}
    where attr_flag=9
    and auction_sku=''";
$db_indus->createCommand($sql)->execute();

现将现有评论的标志位更新到中间状态9,与后续插入的comment_id隔离开来

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容