首页 > 解决方案 > 事务中的触发器和 MEMORY 表不起作用?

问题描述

MariaDB 10.4.13

1.

CREATE TABLE IF NOT EXISTS `zm_sman_updt` (
    `sman_id` INT(11) NOT NULL DEFAULT 0,
    `updated_at` TIMESTAMP NULL DEFAULT NULL,
    PRIMARY KEY (`sman_id`) USING HASH
)
ENGINE = MEMORY;
CREATE TABLE `ss_lineup_cell` (
...
    `sman_id` MEDIUMINT(8) UNSIGNED NULL DEFAULT NULL,
...
)
ENGINE=InnoDB;
CREATE PROCEDURE `update_at_sman`(param_sman_id INT, mx_time_flash INT)
    MODIFIES SQL DATA
  BEGIN
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    SET @update_at_sman_error = 123;

    INSERT INTO `zm_sman_updt` (`updated_at`, `sman_id`)
        VALUES (CURRENT_TIMESTAMP(), param_sman_id)
            ON DUPLICATE KEY UPDATE `updated_at`=VALUES(`updated_at`);
    ...
        
CREATE TRIGGER `update_lineup_cell`
    AFTER UPDATE ON
    ss_lineup_cell FOR EACH ROW
    BEGIN
        IF NEW.sman_id <> OLD.sman_id THEN
            CALL update_at_sman(NEW.sman_id, 180);
        END IF;
END

我的应用程序发送这些命令

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
...
INSERT INTO `ss_lineup_cell` (`lineup_id`, `cell_id`) VALUES (17040, 1)
... 
UPDATE `ss_lineup_cell` SET `sman_id`=1188 WHERE (`lineup_id`=17040) AND (`cell_id`=1)
...
COMMIT;

ss_lineup_cell.sman_id 是 1188

但是 zm_sman_updt 表是空的

如果我

CALL update_at_sman(1188, 180)

从 sql 客户端然后 zm_sman_updt 包含适当的新行

事务中的触发器和 MEMORY 表不起作用?我没有在mysql的文档中找到它...

触发器和事务中的 InnoDB 表工作正常,我有一些这样的结构,它在更新付款后更新用户余额

标签: mysqlmariadb

解决方案


这与内存表或事务无关(尽管为了完整起见,请注意内存表不支持事务,因此如果您回滚事务,则内存表中可能还有剩余的碎片。)。

问题是触发器中的以下行:

IF NEW.sman_id <> OLD.sman_id THEN

OLD.sman_idnull你的场景中。如果您null使用<>(或类似的运算符)与任何东西进行比较,结果将是null,请参见MySQL 与 null 值的比较,因此您if的 - 条件不正确,并且不会调用该过程。

Alan Fullmers answer中所述,您可以简单地使用null-safe 相等运算符 <=>并将该行替换为

IF NOT (NEW.sman_id <=> OLD.sman_id) THEN

虽然<=>看起来有点像“不平等”,但它意味着平等,所以不要忘记NOT.


推荐阅读