【问题标题】:Are Triggers Based On Queries Atomic?基于查询的触发器是原子的吗?
【发布时间】:2013-10-22 16:20:35
【问题描述】:

我有一个有序列号的表。此序列号将更改,引用自动编号将不起作用。我担心触发器的值会发生冲突。如果两个事务同时读取。

我已经对 3 个连接进行了模拟测试,每个连接有大约 100 万条记录,并且没有冲突。

CREATE TABLE `aut` (
  `au_id` int(10) NOT NULL AUTO_INCREMENT,
  `au_control` int(10) DEFAULT NULL,
  `au_name` varchar(50) DEFAULT NULL,
  `did` int(10) DEFAULT NULL,
  PRIMARY KEY (`au_id`),
  KEY `Did` (`did`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1

TRIGGER `binc_control` BEFORE INSERT ON `aut` 
FOR EACH ROW BEGIN
SET NEW.AU_CONTROL = (SELECT COUNT(did)+1 FROM aut WHERE did = NEW.did);
END;

【问题讨论】:

  • SELECT COUNT(*)+1 --- 这真是个坏主意。 au_control 应该指什么?
  • 如果碰撞可能是个问题,那么创建UNIQUE(did, au_control) 似乎是明智的。我不确定触发器中的选择是否是原子的,我会假设它们是 not
  • 你可以定义你的PRIMARY KEY(did,au_control),第二个作为自动增量字段,但它有一些缺点(1)你丢失了au_id列,但是一个真正的主键而不是一个代理可能会更好,(2) 表 必须 是 MyISAM,因为 InnoDB 不支持它,这有严重的缺点。 See this fiddle
  • @Wrikken 感谢您的回答。我不知道 MyIsam 会那样做。我对小提琴的挑战是我失去了唯一识别记录的能力。要使用这种方法,我现在需要同时引用序列和 DID。更新序列号时,如果发生错误,我可能会丢失我的记录站点。

标签: mysql triggers


【解决方案1】:

是的,如果两个会话同时运行触发器,这会受到竞争条件的影响。您不应该使用此解决方案。

它可能不会在测试期间发生,但您可以假设它在生产期间发生。 :-)

有句老话,One in a million is next Tuesday

【讨论】:

    【解决方案2】:

    从技术上讲,是的。它是原子的,初始语句和所有副作用都作为同一个事务提交。

    但是,根据隔离级别,您的查询可能会出错。如果内存可用,MySQL 在目录中有一个缓存值,但如果您在并发事务中使用不可序列化的隔离读取它,这个缓存可能会变得陈旧。

    【讨论】:

      【解决方案3】:

      即使在显式隔离事务中,仍然存在竞争条件,您最终可能会得到重复的 au_control 值。 count(*) 对性能来说会很糟糕。如果您正在尝试这样做,有更好的方法来获得单调递增的 guid。

      【讨论】:

        【解决方案4】:

        MySQL UUID_SHORT() 函数可能对您有用。它是原子的,每次调用时都会生成一个 ever_incrementing BIGINT UNSIGNED 值,但前提是您不停止服务器,将时钟及时设置为早于或接近上一次启动的时间(取决于你多久调用一次)并再次启动服务器,或者将@@server_id的值更改为LSB较低的值。

        http://dev.mysql.com/doc/refman/5.6/en/miscellaneous-functions.html#function_uuid-short

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-11-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多