SELECT中的Mysql死锁..如果没有INSERT存在

时间:2015-05-01 12:50:32

标签: mysql transactions deadlock

我有一个简单的拆分测试表:

CREATE TABLE `tracked_split_test_track_variant` (
  `tracked_split_test_id` int(10) unsigned NOT NULL,
  `track_id` bigint(20) unsigned NOT NULL,
  `variant` char(1) NOT NULL,  
  PRIMARY KEY (`tracked_split_test_id`,`track_id`),
  KEY `tracked_split_test_track_variant_1` (`tracked_split_test_id`),
  KEY `tracked_split_test_track_variant_2` (`track_id`),
  CONSTRAINT `fk_tracked_split_test_track_variant_2` 
    FOREIGN KEY (`track_id`) 
    REFERENCES `track` (`id`)
    ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `fk_tracked_split_test_track_variant_1` 
    FOREIGN KEY (`tracked_split_test_id`) 
    REFERENCES `tracked_split_test` (`id`) 
    ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8

其中变体是随机的A或B.

当系统询问“我应该向哪个用户显示该用户?”时我希望发生以下事情:

  • SELECT属于当前tracked_split_test_track_varianttrack的{​​{1}}
  • 如果不存在记录,请创建一个包含随机变体且tracked_split_test
  • 的新记录

目前,我在事务中运行INSERT和(可选)SELECT查询:

INSERT

    SELECT * 
      FROM tracked_split_test_track_variant
     WHERE track_id = :track_id
       AND tracked_split_test_id = :tracked_split_test_id
FOR UPDATE

我已将 INSERT INTO tracked_split_test_track_variant VALUES (:track_id, :tracked_split_test_id, :variant) 添加到FOR UPDATE,以便如果两个事务以相同的详细信息运行..我不会尝试两次SELECT

即使我尽快承诺,我现在也会陷入僵局。我做错了吗?

1 个答案:

答案 0 :(得分:0)

由于元组在此事务之外是不可变的,因此我使用显式命名锁来提出以下解决方案:

SELECT GET_LOCK('tracked_split_test_track_variant-xxx-yyy',30);

SELECT * 
  FROM tracked_split_test_track_variant
 WHERE tracked_split_test_id = :tracked_split_test_id
   AND track_id = :track_id

     [
INSERT 
  INTO tracked_split_test_track_variant
VALUES (:track_id, :tracked_split_test_id, :variant)
     ]

    DO RELEASE_LOCK('tracked_split_test_track_variant-xxx-yyy');

其中xxxtracked_split_test_idyyytrack_id

我很想知道是否有更好的解决方案。