为什么MySQL中可以多次成功获取同一个GET_LOCK锁?
MySQL
GET_LOCK 重复调用返回1的核心原因 1. 锁本身的可重入特性
MySQL的GET_LOCK()属于会话级命名锁,原生支持重入逻辑:同一个数据库连接(会话)已经持有某名称的锁时,重复调用GET_LOCK()获取同名锁会直接返回成功(返回值1),不会触发等待也不会返回失败。只有不同会话尝试获取已被持有的锁时,才会在等待超时后返回0。
同时重入次数会被计数,你调用多少次GET_LOCK()获取同名锁,就需要调用对应次数的RELEASE_LOCK()才能真正释放该锁。如果你的Scala函数多次调用时复用的是同一个数据库连接,就会出现你观察到的重复调用都返回1的情况。
2. 连接池回收连接导致锁提前失效
如果你的服务集成了数据库连接池(如HikariCP、C3P0等),你的函数逻辑可能仅在执行SELECT GET_LOCK('foo',5);时临时从池中借用连接,SQL执行完成后连接就被归还给了连接池。此时MySQL会自动释放该会话持有的所有GET_LOCK锁,你下一次调用函数时拿到的是新的空闲连接,自然可以再次成功获取锁。
注意:
GET_LOCK的生命周期完全和数据库会话绑定,事务提交、回滚都不会释放该锁,只有会话断开、主动调用RELEASE_LOCK()、或者同一会话调用GET_LOCK()获取其他名称的锁时,原锁才会被释放。
排查验证方法
- 调整函数逻辑,在同一个数据库连接会话内连续执行两次
SELECT GET_LOCK('foo',5);,如果第二次返回1,即可确认是可重入特性导致的现象 - 每次执行
GET_LOCK后同步执行SELECT CONNECTION_ID();打印当前会话ID,如果两次调用返回的ID不一致,即可确认是连接池回收连接导致锁被提前释放
内容的提问来源于stack exchange,提问作者Greg
相关产品推荐
相关产品推荐

