4

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

我已经对 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;
4

4 回答 4

3

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

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

有句老话,百万分之一是下周二

于 2013-10-21T22:13:40.230 回答
0

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

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

于 2013-10-21T22:14:30.220 回答
0

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

于 2013-10-21T22:24:32.423 回答
0

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

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

于 2013-10-22T03:51:00.100 回答