【问题标题】:Synchronization of queries to a MariaDB database将查询同步到 MariaDB 数据库
【发布时间】:2020-04-20 07:57:59
【问题描述】:

由于一些高可用性考虑,我设计了一个系统,其中多个进程将通过数据库进行通信/同步(最有可能是 MariaDB,但我愿意研究 PostgreSQL 和 MySQL 选项)。

已确定的要求之一是进程必须从数据库中获取一项工作,而不能让另一个进程同时获取相同的工作。

具体来说,这是我想到的竞争条件:

  1. 进程 A 启动 SQL 事务并运行 SELECT * FROM requests WHERE ReservedTS IS NULL ORDER BY CreatedTS LIMIT 100。这里ReservedTSCreatedTSDATETIME 列,用于存储工作提交进程创建工作片段的时间,并相应地保留工作执行进程。
  2. 进程 B 启动事务,运行相同的查询并获得相同的结果集。
  3. 进程 A 运行 UPDATE requests WHERE id IN (<list of IDs selected above>) AND ReservedTS IS NULL SET ReservedTS=NOW()
  4. 进程 B 运行相同的查询,但是,由于其事务有自己的数据快照,ReservedTS 对进程 B 将不为空,因此项目被保留两次。
  5. 进程 A 提交事务。
  6. 进程 B 提交事务,覆盖进程 A 的值。

您能帮忙解决上述数据竞争吗?

【问题讨论】:

  • 我预计 6) 会失败。
  • @jarlh,为什么?这是在某处指定的吗?我想阅读更多内容。

标签: sql database concurrency mariadb race-condition


【解决方案1】:

您可以通过使用排他锁轻松做到这一点:

为简化测试表:

CREATE TABLE t1 (id int not null auto_increment primary key, reserved int);
INSERT INTO t1 VALUES (0,0), (1,0);

流程A:

BEGIN
SELECT id, reserved from t1 where id=2 and reserved=0 FOR UPDATE;
UPDATE t1 SET reserved=1 WHERE id=2 and reserved=0;
COMMIT

如果进程 B 在进程 A 完成事务之前尝试更新相同的条目,它必须等到锁被释放(或发生超时):

update t1 set reserved=1 where id=2 and reserved=0;
Query OK, 0 rows affected (12.04 sec)
Rows matched: 0  Changed: 0  Warnings: 0

如您所见,进程 B 没有更新任何内容。

【讨论】:

  • 感谢您的回答。你能检查你的表创建语句吗?它似乎缺少字段a,然后插入语句应该插入带有a=2 的内容,以便以后的查询起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-24
  • 2011-04-23
  • 2014-05-21
  • 1970-01-01
  • 2011-09-29
  • 1970-01-01
  • 2019-03-11
相关资源
最近更新 更多