我想知道业界用于生成序列号的一般做法。
即从表中获取最大值。增加它并将其存储回去。
为了使其工作,应使用哪种隔离级别和/或锁定方案。
我认为可序列化应该可以正常工作。但它只会阻止对表的更新。仍然可以进行选择。因此,将更新的值可能相同。我们如何避免这种情况?
谢谢!
最佳答案
您在事务范围内所做的任何事情都受制于竞争条件。
因此,您为获取上次使用的值、增加它并将其存储在新行中而执行的任何 SQL 查询都意味着两个并发客户端可以获取相同的值并尝试使用它,从而导致重复键。
有几种解决方法:
Locking.如果您使用
SELECT ... FOR UPDATE
(如@Daniel Vassallo 所述) ,每个客户端都会在他们读取的行上设置独占锁
Use auto-increment.这种机制保证没有竞争条件,因为新值的分配是在不考虑事务范围的情况下发生的。作为一个好处,没有两个并发客户端将获得相同的值。不过,这意味着回滚不会撤消值的分配。
LAST_INSERT_ID()
函数返回当前 session 分配的最后一个自动增量值,即使其他并发客户端也在同一表或不同表中生成值。使用外部解决方案。生成主键值不是使用 SQL,而是使用应用程序中的其他系统。您有责任防止竞争条件。例如,您可以使用计数信号量。
使用伪随机的唯一 ID。主键需要是唯一的,但不需要是单调递增的整数。有些人使用
UUID()
函数生成一个随机的 128 位数字,几乎可以保证没有重复。但是您的主键必须使用更大的数据类型,例如CHAR(36)
或BINARY(16)
并且不方便编写临时查询。SELECT * FROM MyTable WHERE id = '6ccd780c-baba-1026-9564-0040f4311e29';
您在评论中提到您“阅读了一些关于使用自动增量的负面信息”。当然,任何语言的任何特性都有做和不做的。这并不意味着我们不应该使用这些功能,而是意味着我们应该学习如何正确使用它们。
您能描述一下您对自动增量的担忧或任何负面影响吗?也许这个线程上的人可以解决这些问题。
关于mysql - 应该使用哪种锁定方案和隔离级别来生成序列号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3325458/