【发布时间】:2015-06-08 14:02:39
【问题描述】:
TL;DR:
SQL 小提琴:http://sqlfiddle.com/#!2/0bec3/1
为什么row_was_updated 更新了?
背景
我有一个守护进程,它在多个主机上运行多个实例(每个主机一个守护进程实例)以实现冗余。在任何时候,只有这些实例中的一个应该是活动的。所有其他人必须等待活动实例死亡,然后才能接管“活动”状态。
我有一个 MySQL 表,用于跟踪所有守护程序实例,并跟踪哪个实例是活动的。第一个将 1 值插入active 列的实例成为活动实例。所有实例不断将当前时间写入last_active 列。有一个 MySQL 触发器可以删除 last_active 列的值超过 30 秒的任何行。如果活动实例未能更新其last_active 值 - 因为它崩溃了 - 它的行将被数据库删除,另一个实例将成为活动实例。
表格
CREATE TABLE `DT_ActiveCommandModules` (
`host` INT(11) NOT NULL DEFAULT '0',
`name` VARCHAR(50) NOT NULL DEFAULT '0' COLLATE 'latin1_general_cs',
`active` BIT(1) NULL DEFAULT NULL,
`last_active` TIMESTAMP NULL DEFAULT NULL,
`row_was_updated` BIT(1) NULL DEFAULT NULL,
PRIMARY KEY (`host`, `name`),
UNIQUE INDEX `each command module can have only one active instance` (`name`, `active`)
);
想法
每个实例运行相同的 insert..on 重复键更新 查询,并具有自己的值。如果查询失败,实例知道它没有成为活动实例,因此必须等待一段时间再试一次。如果查询成功,则实例为活动实例,其last_active值已更新。
例如,名为 TEST 的守护程序的第一个实例(在主机 1 上)执行此查询(在一个空表上):
INSERT INTO DT_ActiveCommandModules
(host, name, active, last_active, row_was_updated)
VALUES
(1,'TEST',1,now(), 0)
ON DUPLICATE KEY UPDATE
active=1,
last_active=NOW();
并成为活动实例。然后守护程序 TEST 的第二个实例(在主机 2 上)执行此查询:
INSERT INTO DT_ActiveCommandModules
(host, name, active, last_active, row_was_updated)
VALUES
(2,'TEST',1,now(), 0)
ON DUPLICATE KEY UPDATE
active=1,
last_active=NOW();
问题
我预计第二个查询会因为 (name,active) 上的 UNIQUE 约束而失败。奇怪的是它并没有失败。更奇怪的是,它会继续更新主机 1 上实例的 last_active 值。
所以首先它不匹配唯一键,但显然它确实匹配主键(具有不同的值,host=1 与 host=2)???
我创建了这个 SQL 小提琴来显示行为:http://sqlfiddle.com/#!2/0bec3/1
我添加了row_was_updated 位以显示来自模拟的第二个实例的查询确实更新了第一个实例的行。我真的不明白为什么会这样。
问题
- 为什么第二个查询不匹配唯一键?
- 为什么会匹配不同值的主键?
- 如何修复查询以执行我想要的操作? ;-)
有什么想法吗?
【问题讨论】:
标签: mysql