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

Mysql 序列号生成应使用哪种锁定方案和隔离级别?,mysql,Mysql,我想知道行业中生成序列号的一般做法 i、 e.从表格中获取最大值。增加并存储它 为了使其工作,应使用哪种隔离级别和/或锁定方案 我认为serializable应该可以很好地工作。但它只会阻止表的更新。仍然可以进行选择。因此,将被更新的值可以是相同的。我们如何避免这种情况 谢谢 一般做法不是这样做,而是使用自动递增字段或自动生成的序列字段,或数据库提供的任何工具。有点不清楚,您确定要从RDBMS获取序列号吗?或者你可以用你最喜欢的编程语言来实现这个概念。关键取决于您计划如何分享价值 与其使用MAX

我想知道行业中生成序列号的一般做法

i、 e.从表格中获取最大值。增加并存储它

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

我认为serializable应该可以很好地工作。但它只会阻止表的更新。仍然可以进行选择。因此,将被更新的值可以是相同的。我们如何避免这种情况


谢谢

一般做法不是这样做,而是使用自动递增字段或自动生成的序列字段,或数据库提供的任何工具。

有点不清楚,您确定要从RDBMS获取序列号吗?或者你可以用你最喜欢的编程语言来实现这个概念。关键取决于您计划如何分享价值

与其使用MAX(),不如使用一个简单的具有该值的一行一列表。 实现一个增量和获取函数,并在任何地方使用它。如果您的DBMS支持,这是存储过程或触发器的理想用途。

请注意,使用InnoDB的默认隔离级别,您可以简单地使用语法,如下所示:

测试架构:

CREATE TABLE your_table (id int) ENGINE=INNODB;
INSERT INTO your_table VALUES (1), (2), (3);
然后,我们可以执行以下操作:

START TRANSACTION;

SELECT @x := MAX(id) FROM your_table FOR UPDATE;

+---------------+
| @x := MAX(id) |
+---------------+
|             3 |
+---------------+
1 row in set (0.00 sec)
在不提交事务的情况下,我们启动另一个单独的会话,并执行相同的操作:

START TRANSACTION;

SELECT MAX(id) FROM your_table FOR UPDATE;
在运行此查询之前,数据库将等待上一个会话中设置的锁被释放

因此,切换到上一个会话,我们可以插入新行并提交事务:

INSERT INTO your_table VALUES (@x + 1);

COMMIT;
在第一个会话提交事务后,将解除锁定,并返回第二个会话中的查询:

+---------+
| MAX(id) |
+---------+
|       4 |
+---------+
1 row in set (8.19 sec)

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

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

有几种解决方案:

  • 如果使用
    SELECT。。。更新
    (如@Daniel Vassallo所述)

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

  • 使用外部解决方案。不使用SQL而是使用应用程序中的其他系统生成主键值。你有责任保护自己不受比赛条件的影响。例如,您可以使用计数信号量

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

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

  • 你在评论中提到,你“读到了一些关于使用自动增量的负面消息”。当然,任何语言中的任何特性都有“做”和“不做”的地方。这并不意味着我们不应该使用这些特性——而是意味着我们应该学会如何正确地使用它们


    你能描述一下你对自动增量的担忧或任何负面的事情吗?也许这条线上的人可以解决这些问题。

    我正在考虑用这种方式实现它。1) 从DB中获取当前值(存在于特定列中。将不使用max函数)2)增加步骤1中获取的值3)使用新值更新DB,但是,如果我必须这样使用它,则两个不同的连接可能最终更新DB中的相同值。我明白了。我的数据库是mysql。最初我考虑使用自动递增字段。但是读了很多关于它们的负面的东西,并决定不使用它。我只是公然假设你想要一个除了自动递增字段之外的第二个序列。你对自动递增的确切担忧是什么?谢谢,伙计。我不希望在生成的值中出现较大的差距。因此,我考虑应用我自己的解决方案。非常感谢您的详细解释。我曾读到,在某些情况下,服务器生成的值可能存在很大的差异。因为我希望表中有顺序数据,所以我想写自己的解决方案。但是,在阅读了这里的评论之后,我认为使用自动递增字段是最好的方法。你会建议哪一种?使用选择实现它。。。对于更新或使用自动增量?我绝对建议使用自动增量。锁定可以阻止并发读卡器(取决于您的事务隔离级别)。我使用
    UUID()
    函数添加了另一个解决方案,但我仅出于完整性考虑才包含它。我仍然建议使用自动增量。谢谢,伙计。我想这应该能解决我的问题。你喜欢哪一个?以这种方式实现还是使用自动增量字段?@rocksolid:在大多数情况下,我会选择自动增量字段,这是比尔·卡温在回答中概述的原因。谢谢丹尼尔。自动递增应为!:-)