MySql:用于递增数字的正确事务隔离级别

MySql:用于递增数字的正确事务隔离级别,mysql,transactions,increment,isolation-level,transaction-isolation,Mysql,Transactions,Increment,Isolation Level,Transaction Isolation,假设DB中有这样一个表: id code a8e09395-771c-4c6b-bb49-4921eeaf3927 2018-1 726b1390-b502-11e8-96f8-529269fb1459 2018-2 7a7ac7a6-b502-11e8-96f8-529269fb1459 2018-3 81758ea6-b502-11e8-96f8-529269fb1459 2019-1 假设

假设DB中有这样一个表:

id                                       code
a8e09395-771c-4c6b-bb49-4921eeaf3927    2018-1
726b1390-b502-11e8-96f8-529269fb1459    2018-2
7a7ac7a6-b502-11e8-96f8-529269fb1459    2018-3
81758ea6-b502-11e8-96f8-529269fb1459    2019-1
假设有多个客户端写入此表

对于“代码”列,我们希望确保它遵循严格的“今年第n个”模式

所有客户端应该使用的正确事务隔离级别是什么

----更新----2018-09-11 11:31:24---------

对上述事务进行了快速测试

mysql2> begin;
mysql2> select max(code) from mytable where code like '2018-%' for update;
(waits for lock)
我启动了两个控制台,然后运行上面的代码,我将它们都运行到读取代码列的行

然后让其中一个更新代码列,它将等待锁定

然后我让另一个更新代码列,它将死锁并回滚

现在,第一个人的锁被解除,可以提交了


因此,看起来这种事务隔离可以防止它们互相攻击,对吗?

您需要通过锁定来解决这个问题

不管事务隔离级别是什么

在一次会议上:

mysql1> begin;
mysql1> select max(code) from mytable where code like '2018-%' for update;
输出:

+-----------+
| max(code) |
+-----------+
| 2017-3    |
+-----------+
在第二个会话中,尝试相同的选择更新。它暂停,等待第一个会话事务持有的锁

mysql2> begin;
mysql2> select max(code) from mytable where code like '2018-%' for update;
(waits for lock)
在第一个会话中,使用select返回的值计算下一个值。然后插入下一行并提交

mysql1> insert into mytable values (uuid(), '2018-4');
mysql1> commit;
第二个会话在第一个会话中的提交之后立即返回。它正确返回新的max代码:

+-----------+
| max(code) |
+-----------+
| 2017-4    |
+-----------+
现在,第二个会话有了锁,它可以插入下一行,而不必担心任何其他会话会潜入select和insert之间


如果您使用
进行更新
来锁定行并确保事务连续工作,则任何事务隔离都将起作用。

“对于“code”列,我们希望确保它遵循严格的“今年第n年”模式。这不能通过事务隔离来解决。。您可以做的是触发对代码列进行计数和更新,并向除代码列之外的每一列授予列权限。。不确定撤销列权限是否会覆盖表权限,MySQL文档中也没有解释。谢谢回复。我不明白为什么“不管事务隔离级别是什么”。假设两个客户机试图写入此表,它们都使用具有可序列化级别的事务。这将确保这两个客户不会互相攻击,对吗?试试看,使用我展示的示例步骤!您应该在本地或沙箱环境中运行MySQL实例以进行测试。刚刚做了一个快速测试,请参阅上面更新的文本。(无法将代码粘贴到注释中,格式将混乱:()是的,SERIALIZABLE使每个选择都进入共享模式下的选择…锁定。这在手册中有:但是如果您执行交错语句-在两个窗口中执行选择,然后在两个窗口中尝试更新-您将遇到死锁。要避免此情况,请使用
SELECT…FOR UPDATE
,如我所示。