如果在mysql中并发运行,我的update语句可以工作吗?

c90pui9n  于 2021-06-19  发布在  Mysql
关注(0)|答案(3)|浏览(419)

我看到许多类似的问题,但我仍然不能完全确定我是否正确。
我们有一个应用程序,它启动一个作业来批量发送许多消息。消息传递状态稍后将分批接收,并且不按特定顺序接收。
表结构是like:-

CREATE TABLE `message` (
  `pk` char(32) NOT NULL DEFAULT '',
  `job_id` varchar(40) DEFAULT NULL,
  `status` varchar(40) DEFAULT NULL,
  `update_date` datetime DEFAULT NULL,
  PRIMARY KEY (`pk`),
  KEY `job_id` (`job_id`),
  KEY `status` (`status`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

这些记录最初是用 status 设置为空。其值应从null更改为 sent 然后到 delivered . 以下语句用于更新记录。
当要设置的状态为- delivered ```
Update message SET status = 'delivered', update_date = Now()
WHERE job_id = :someId

当要设置的状态为- `sent` ```
Update message SET status = 'sent', update_date = Now()
    WHERE job_id = :someId AND status IS NULL

问题是,可能有两个线程同时尝试设置 status “已发送”和“已交付”的相同记录。在这种情况下,“已交付”是最终状态,因此我们希望最终获胜。
上面的语句在mysql或mariadb中能保证这一点吗?

w1e3prcc

w1e3prcc1#

Update message SET status = 'delivered', update_date = Now()
    WHERE job_id = :someId
      AND status = 'sent'    -- add this??

(mysql和mariadb在这方面应该没有区别。)

uurity8g

uurity8g2#

是的,在mysql和mariadb中(可能还有任何sql数据库)。对同一行的更新是原子的。
“sent”将覆盖null,但不覆盖“delivered”
“delivered”将覆盖null和“sent”
这就是你想要的。在更新之前,请确保具有给定作业id的消息存在:)

2exbekwf

2exbekwf3#

Update message SET status = 'sent', update_date = Now()
WHERE job_id = :someId
AND status != 'delivered';

相关问题