【发布时间】:2016-07-01 09:36:13
【问题描述】:
我在 MySQL 中有一个事件,我想非常频繁地至少每 30 秒运行一次。
它正在处理包含最近更新记录的队列表中的数据。有时我会收到大量更新。发生这种情况时,事件的运行时间可能比通常的 2-3 秒长。如果它在下一个计划时仍在运行,我希望下一个事件跳过执行。
我能想到的最好方法是创建一个“状态”表,在该表中我在进程开始时将特定键设置为 1,在完成时将其设置回 0。 然后我会更改事件以检查当前状态。
我更愿意做一些比这更好的事情。有没有我完全缺少的功能?
我研究了全局变量,但根据文档,这些似乎只允许用于系统变量。
当前示例代码
这是我目前正在测试的示例代码。
acca_sync: BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN
GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE,
@errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;
SET @full_error = CONCAT("ERROR ", @errno, " (", @sqlstate, "): ", @text);
call pa.log(concat("acca-acc_sync"," - Error - ", ifnull(@full_error, "no error message")));
UPDATE `acca`.`processing_state`
SET `value` = 0
WHERE `key` = 'acca_sync';
END;
call pa.log(CONCAT("Started acca_sync @ ", NOW()));
SELECT `value`
into @is_locked
from `acca`.`processing_state`
where `key` = 'acca_sync';
IF @is_locked = 0 THEN
UPDATE `acca`.`processing_state`
SET `value` = 1
WHERE `key` = 'acca_sync';
ELSE
CALL pa.log(CONCAT("acca_sync deferred due to active sync. @ ", NOW()));
LEAVE acca_sync;
END IF;
call acca.event_sync();
call pa.log(CONCAT("Completed acca_sync @ ", NOW()));
UPDATE `acca`.`processing_state`
SET `value` = 0
WHERE `key` = 'acca_sync';
END
表格锁定
根据评论,我想解释一下为什么我不使用表锁。我对表锁的经验是有限的,所以我希望以下内容是正确且有意义的。
源数据表
我有通知队列表中的更新的触发器。这些是我的源数据表,我从中读取数据以进行处理。
我的理解是这些表上的READ 锁定不会锁定任何其他刚刚读取的事件。
如果我要使用WRITE 锁,我会阻止对我当前不访问的任何行的任何更新。
目标数据表
我有多个数据源来处理不同事件中的数据。这些将在目标表中修改的行。可能有两个不同的事件同时运行写入同一个表,所以我不想人为地阻塞目标表
其他表格
我可以创建一个假表,我只是为了设置然后检查锁的存在而拥有它。这似乎很荒谬,我宁愿创建一个带有lock_key 和is_locked 列的单表锁,我每次都查询。
【问题讨论】:
-
你考虑过表锁吗?
-
我实际上有 - 抱歉没有提及。问题是源数据很混乱(经常错过一些稍后可用的参考数据。)所以我必须锁定一些表,我想将所有这些都保存在一个事件中,因为顺序是我最好的机会一口气完成所有处理。所以我最好的办法是在单个表上创建一个锁,阻塞整个进程。
-
您需要更好地定义您希望这两个事件如何一起发挥作用。当你这样做时,我可以提出一些建议。
-
我有代码可以很好地做到这一点,但它就像 500 行代码。主要是大约 100 行,但为了说明它有 4 个表和 3 个竞争事件,并且有据可查,行数激增。
标签: mysql mysql-event