应该使用哪种锁定方案和隔离级别来生成序列号?

use*_*562 4 mysql

我想知道业界用于生成序列号的一般做法。

即从表中获取最大值。增加它并存储回来。

为了使其工作,应使用哪种隔离级别和/或锁定方案。

我认为可序列化应该可以正常工作。但它只会阻止对表的更新。仍然可以进行选择。因此,将更新的值可能是相同的。我们怎样才能避免这种情况呢?

谢谢!

Bil*_*win 7

您在事务范围内所做的任何事情都受到竞争条件的约束。

因此,您为获取最后使用的值、递增该值并将其存储在新行中而执行的任何 SQL 查询都意味着两个并发客户端可以获取相同的值并尝试使用它,从而导致重复的键。

对此有几种解决方案:

  1. 锁定。 如果您使用,每个客户端都会在它们读取的行上设置独占锁SELECT ... FOR UPDATE(如 @Daniel Vassallo 所描述)

  2. 使用自动增量。 这种机制保证没有竞争条件,因为新值的分配发生时不考虑事务范围。这样做的好处是,没有两个并发客户端会获得相同的值。但这意味着回滚不会撤消值的分配。该LAST_INSERT_ID()函数返回当前会话分配的最后一个自动增量值,即使其他并发客户端也在同一表或不同表中生成值。

  3. 使用外部解决方案。 不使用 SQL 而是使用应用程序中的其他系统生成主键值。您有责任防止出现竞争情况。例如,您可以使用计数信号量。

  4. 使用伪随机的唯一 ID。 主键必须是唯一的,但不需要是单调递增的整数。有些人使用该UUID()函数生成一个随机的 128 位数字,实际上可以保证没有重复。但是,您的主键必须使用更大的数据类型,例如CHAR(36)or BINARY(16),并且编写临时查询很不方便。

    从 MyTable 中选择 *,其中 id = '6ccd780c-baba-1026-9564-0040f4311e29';

您在评论中提到您“读到了一些关于使用自动增量的负面信息”。当然,任何语言的任何功能都有该做和不该做的事情。这并不意味着我们不应该使用这些功能——而是意味着我们应该学习如何正确使用它们。

您能描述一下您的担忧或有关自动增量的任何负面影响吗?也许这个帖子上的人可以解决这些问题。