MySQL定时事件锁机制疑问:异常释放与重复锁问题
MySQL事件并发控制与GET_LOCK()常见疑问解答
一、事件执行异常时,GET_LOCK()的锁会自动释放吗?
- MySQL的每个事件执行都是独立创建的新会话,事件执行完成(无论正常结束还是异常终止),这个会话会立刻关闭。
- GET_LOCK()创建的是会话级锁,只要持有锁的会话终止,MySQL会自动释放该锁,不需要依赖手动调用
RELEASE_LOCK()。 - 所以即使
some_event_body触发异常(比如引用不存在的列),事件会话会直接终止,锁会被自动回收,不会出现锁一直持有的情况。不过手动调用RELEASE_LOCK()是良好的编码习惯,能在正常执行时提前释放锁。
二、为什么进程列表中会出现多个会话等待同一个命名锁?
你看到的多个会话处于User lock状态是正常现象:
- GET_LOCK()的规则是同一时间仅允许一个会话持有同名锁,当其他会话调用
GET_LOCK('test', -1)时,因为超时参数设为-1(无限等待),这些会话会进入等待状态,直到持有锁的会话释放锁。 - 你之前未添加“获取不到锁就放弃”的逻辑,事件到调度时间就启动新实例,前一个实例还没释放锁时,新实例就会去抢锁,抢不到就无限等待,最终导致进程列表中出现大量等待锁的会话。
优化建议:实现“获取不到锁直接放弃”的逻辑
你当前的代码用了GET_LOCK('ev_test', -1),这会让实例无限等待锁,不符合你“锁存在时直接放弃”的需求。可以把超时参数改为0(立即返回),这样获取不到锁时直接触发SIGNAL终止事件:
IF GET_LOCK('ev_test', 0) IS NOT TRUE THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'failed to obtain lock; not continuing; '; END IF; some_event_body; RELEASE_LOCK('ev_test');
这样新的事件实例会在获取不到锁时直接终止,不会进入等待队列,避免并发排队导致的数据异常。
内容的提问来源于stack exchange,提问作者Danish Hasan
相关产品推荐
相关产品推荐

