我有一个包含序列号的表。此序列号将更改,并且引用自动编号将不起作用。我担心触发器的值会发生碰撞。如果两个交易同时读取。
我已经在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;
答案 0 :(得分:3)
是的,如果两个会话同时运行触发器,则会受到竞争条件的影响。你不应该使用这个解决方案。
在测试过程中可能不会发生,但您可以假设将在生产过程中发生。 : - )
答案 1 :(得分:0)
技术上,是的。它是原子的,初始语句加上所有副作用都是作为同一个事务提交的。
但是,根据隔离级别,查询的任何内容都可能出错。如果内存服务,MySQL在目录中有一个缓存值,但如果你在并发事务中使用非可序列化隔离读取它,这个缓存可能会变得陈旧。
答案 2 :(得分:0)
即使在显式的隔离事务中,仍然存在竞争条件,您可以最终获得重复的au_control值。 count(*)对性能来说太可怕了。如果这是你想要做的事情,有更好的方法来获得单调增加的指导。
答案 3 :(得分:0)
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