假设在表t中有一行id等于1。
如果运行以下sql,则得到的结果等于1(当c列为0时):
SELECT NEXT_ID(1)
但是,如果运行这个命令,结果是1,而不是0(因为表t中没有id=2的行):
SELECT NEXT_ID(2)
下一个id函数:
CREATE FUNCTION NEXT_ID(id INT)
RETURNS VARCHAR(15)
BEGIN
DECLARE counter BIGINT DEFAULT 0;
UPDATE t SET c = (@counter := c +1) WHERE ID = id;
return @counter;
END;
我在这里的意图是创建一个计数器,作为一个原子操作递增一个值。那么,为什么在下一个\u id(2)上得到大于0的值?似乎计数器变量已存储在会话中。。。
在多线程应用程序中使用它安全吗?
1条答案
按热度按时间ie3xauqp1#
如果你
DECLARE counter
那你不应该用@counter
引用变量。在mysql存储函数中,声明的变量没有@
西格尔。变量与@
sigil是用户定义的变量。@counter
是一个不同的变量counter
,尽管它们的拼写相同。在多线程应用程序中这样做安全吗?当然,如果线程通过使用不同的
id
价值观,它们不会冲突(假设id
是唯一的t
表)。即使多个线程使用相同的
id
值,因此需要在t
表中,将发生的情况是,一个将首先到达那里,在行上获得一个锁,并将其递增。第二个线程将等待获取自己的锁,直到第一个线程提交其事务。然后第二个线程将继续,然后将看到c
.所以它是安全的,但是它不允许高吞吐量。争用同一线程的线程
id
必须排队等待锁的当前持有者提交其事务。如果您希望多个线程并行工作,您会发现这会成为一个瓶颈。这就是为什么
AUTO_INCREMENT
存在,因为它会短暂锁定计数器以生成新值,但会立即释放锁,而不是等待调用方的事务完成。这允许并发线程继续工作,而不是互相等待。你不能模拟
AUTO_INCREMENT
与UPDATE
操作,这在事务中是必需的。请回复您的意见:
对不起,我忘了
:=
不适用于局部声明的变量。我测试了一下,发现了两种选择:备选方案1:不用费心声明局部变量,只需使用用户定义的变量。
备选方案2:使用局部变量,但设置
LAST_INSERT_ID()
到递增的值。那么SET
该值的计数器局部变量。我测试了两种方法,它们都有效。