【问题标题】:Avoiding collisions on inserting manually incremented receipt number避免在插入手动递增的收据编号时发生冲突
【发布时间】:2013-11-13 13:08:15
【问题描述】:

我有一个查询,每次用户购买时都会从receipts 表中获取当前最高的receipt_counter 号码,以便创建新收据。 receipt_counter 在表中不是唯一的,因为它每年都会重置。

receipt_counter 只是一个整数,用于生成类似于"pos_id"-"receipt_counter"receipt_label
人们有可能在同一个销售点同时购买产品 (pos_id)。

获得新的receipt_counter 的函数如下所示:

SELECT (MAX(receipt_counter) + 1) as next_receipt_counter FROM receipts

问题是当多人同时购买产品时,会触发生成新收据(连同收据编号),有时会发生冲突(多人获得相同的收据编号),因为在检索收据计数器和插入之间存在一些延迟新收据进入数据库。

是否有处理此类问题的最佳实践?我是否需要使用某种死锁,还是我最初的想法有缺陷,我需要改变策略来一起生成收据计数器?

编辑:receipt_counter 需要是一个没有间隙的序列号。

【问题讨论】:

  • 你不能使用序列来生成receipt_counter吗?
  • 如果延迟很低,您可以使用 LOCK TABLE。然后其他用户脚本将等到您解锁该表,即。订单将被写入您的数据库。
  • 不要尝试自己实现序列生成器,让数据库来做吧。见Lolo:s answer。

标签: php mysql sql deadlock database-deadlocks


【解决方案1】:

在检索收据计数器和将新收据插入数据库之间存在一些延迟

您可以更改您的软件,以便在不创建实际收据的情况下代替或检索 ID,它会创建收据(具有“待定”状态或类似的状态),然后检索其 ID。在您当前创建收据的那一刻,您只需将其状态设置为“活动”之类的。

这样做可以消除获取 ID 和存储记录之间的时间间隔,在我看来,这是问题的主要来源。

【讨论】:

    【解决方案2】:

    您可以仅为 id 创建单独的表并在该 id 列上启用 auto_increment。然后分两步添加收据 - 首先将新记录添加到 id 表中,以接收返回生成的 id。然后使用收到的 id 添加实际收据。然后,当您想要重置增量计数器时,只需使用 id 截断表即可。

    【讨论】:

    • 这解决了我的冲突问题,但另一个问题是当同时交易之一失败时,它会在我的receipt_counter 中留下一个“空白”
    【解决方案3】:

    receipt_counter 是否需要增加没有间隙的数字?

    如果增加带有间隔的大数字是可以的,那么从当前日期/时间生成一个数字怎么样?如果你下降到毫秒或纳秒,那么发生冲突的机会就很低了。

    例如:

    2013-11-13 13:08:15.012 -> 1113130815012
    (我省略了年份,因为你说无论如何每年都会重置数字)

    【讨论】:

    • 它需要不断增加的数量而没有间隙
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多