防止并行事务中的重复增量值

Prevent duplicate increment values during parallel transactions

我使用 MySQL 中的交易来存储订单。每个订单都有 OrderID (BIGINT),看起来像这样:XXXXXX0001,最后四位数字递增(1620200001、1620200002、1620200003,...)。

交易工作如下:

start transaction
get new OrderID (increment by 1)
do some stuff
commit/rollback

保存交易最多可能需要几秒钟,如果在很短的时间内创建了多个订单,则可能会向数据库中插入重复的 OrderID。在第一个订单提交之前,第二个订单被分配相同的 OrderID,目前是下一个订单。

防止这种情况的最佳方法是什么? UNIQUE OrderID 并不能解决问题(二阶会回滚)。我可以摆脱事务并更快地保存 OrderID,但这会导致其他潜在问题并且不能完全解决这个问题(只是减少问题发生的可能性)。

如有任何帮助,我们将不胜感激。

了解 AUTO_INCREMENT。在 CREATE TABLE 上的手册中搜索它。这是一个很长的页面,但是 AUTO_INCREMENT 被记录在页面下方的大约 1/4 处。

简而言之,您只需使用列选项声明主键:

CREATE TABLE mytable (
  id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  ...other columns... 
);

初始值为1,或者你可以让它从更高的值开始:

ALTER TABLE mytable AUTO_INCREMENT=1620200001;

具有自动增量列的table 可确保每个并发事务获得唯一的递增值。没有竞争条件,因为 INSERT 获得了一个简短的 table-lock,在此期间它增加了值。与基于事务的锁不同,自增table锁是立即释放的。因此并发会话不必等待您的事务完成。

自增保证唯一。即不会将同一个值分配给多个会话。但是,不能保证分配 个连续 个值。此外,它可能会为一个会话分配一个值,但该会话决定回滚其事务。它分配的值不会返回到任何类型的值队列,因为可能有其他会话同时分配了接下来的几个值。因此,可能会“丢失”值,然后您的 table 会出现“间隙”或不连续的值。

不用担心差距。即使值是连续的,这些也可能发生,因为您稍后可能会删除一行。