MySQL的选择Last_Insert_ID的线程安全性

27

我正在尝试让一些 SQL Server 代码也在 MySQL 上运行,但我刚遇到了这个陷阱。Google 说通常的做法是先执行插入语句,然后使用 last_insert_ID() 函数查询刚刚写入的记录。

然而,在多用户环境下,这种方法似乎不太安全。因为在那个很短的时间窗口内,其他用户可能会插入一些数据并导致返回值错误。那么,如何安全地插入数据并获取插入记录的关键字呢?

1个回答

43

来自 LAST_INSERT_ID(), LAST_INSERT_ID(expr)

生成的ID是在服务器上以每个连接为基础进行维护的。这意味着函数返回给指定客户端的值是该客户端最近一次影响AUTO_INCREMENT列并且是由该客户端执行的语句生成的第一个AUTO_INCREMENT值。即使其他客户端生成了自己的AUTO_INCREMENT值,也不能影响此值。这种行为确保每个客户端都可以检索到自己的ID,并且无需考虑其他客户端的活动,也无需锁定或事务。

因此,除非多个用户的插入恰好通过同一个数据库连接进行,否则您不用担心。


我错过了那个小的每个连接的细节。 - Loren Pechtel
6
这是一个很好的回答。然而,在创建利用连接池的现代应用程序时,提问者仍应注意。连接池解决了为每个数据库交互创建新连接的缓慢性能问题。连接池将在幕后保留连接并不关闭它们,以便其他组件可以重复使用它们以提高性能。如果您没有使用连接池并且按事务基础管理自己的连接,则last_insert_ID()将适用于您,但对于那些使用连接池的人来说,它不是解决方案。 - Russ
2
@Russ,你说“last_insert_id”在连接池中存在问题,对吧?我想试一下这个情况。我正在使用Spring、MySQL、Mybatis和C3P0作为连接池。将c3p0的maxPoolSize和minPoolSize都设置为1,在循环中使用线程插入多条记录。但我发现在这种情况下没有任何问题。所以你能告诉我如何模拟你所说的情况吗? - frank
如果您的maxPoolSize为1,那么它仍然是一个池吗? - Tristan
这也适用于Bash中的echo插入吗?在Bash中,我需要两个echo。一个用于插入,另一个用于Last_Inserted_Id。 - TheAlphaGhost
Node.js怎么样?通常情况下,Node.js服务器(单线程)保持单个DB连接。在这种情况下安全吗?我想这取决于并发连接到Node.js服务器查询DB的顺序,例如,如果连接A进行INSERT A,然后连接B进行INSERT B,那么当INSERT A完成并执行其回调时,它会调用另一个查询SELECT LAST_INSERT_ID(); -- A,在这一点上,如果INSERT B在发送命令SELECT LAST_INSERT_ID(); -- A之前已经完成,则我想A可能会获得错误的B ID。 - tonix

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接