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();
我预计第二个查询会因为(名称,活动)上的UNIQUE约束而失败。奇怪的是,它不会失败。更奇怪的是,它会继续更新主机 1 上的实例的last_active
值。
所以首先它与唯一键不匹配,但显然它 匹配主键(具有不同的值,host = 1 vs host = 2)???
我创建了这个SQL小提示来显示行为:http://sqlfiddle.com/#!2/0bec3/1
我添加了row_was_updated
位以显示来自模拟第二个实例的查询确实更新了第一个实例的行。我真的不明白为什么会这样做。
有什么想法吗?
答案 0 :(得分:0)
PRIMARY KEY
或重复UNIQUE KEY
上的
如果指定ON DUPLICATE KEY UPDATE,则插入一行 会在UNIQUE索引或PRIMARY KEY,MySQL中导致重复值 执行旧行的更新。
所以这里'TEST', 1
匹配唯一约束,与主键的host
部分无关,导致子句更新实际上在另一个主机上活动的实例。