我有一堆连接在一个事务中执行SELECT,另一个执行DDL。mysql手册非常清楚有关如何在事务内获取元数据锁:
为了确保事务的可序列化性,服务器不得允许一个会话对另一个会话中未完成的显式或隐式启动的事务中使用的表执行数据定义语言(DDL)语句。服务器通过获取事务中使用的表上的元数据锁并将这些锁的释放推迟到事务结束之前来实现。表上的元数据锁可防止更改表的结构。这种锁定方法的含义是,在一个事务内的事务正在使用的表在事务结束之前不能在其他会话的DDL语句中使用。
这很有道理,所以我做了这个测试:
connectionA$ begin;
connectionA$ select * from facebook_authorizations;
connectionA$ ....
connectionB$ alter table facebook_authorizations add column foo int default null;
connectionC$ begin;
connectionC$ select * from facebook_authorizations;
connectionA$ commit;
在我的系统上,当connectionA提交时,connectionC执行,而connectionB仍然挂起:它使基于SELECT的转换无法执行。我期望元数据锁定等待列表大致按FIFO顺序进行处理,但事实并非如此。
是否有关于元数据等待队列处理顺序的文档?
尝试重现这种情况,我阻止了会话B,然后阻止了会话C。请注意,如果会话B实际上在获取表上的元数据锁之前正在等待其他事件,则会话C没有理由等待。
已经授予的元数据锁performance_schema
在表中metadata_locks
的LOCK_STATUS
as中可见GRANTED
。
参见文档:https : //dev.mysql.com/doc/refman/8.0/en/metadata-locks-table.html
这有助于查看哪个会话拥有哪个锁。
会话正在等待的元数据锁在同一表中也可见,用LOCK_STATUS
as表示PENDING
。
这有助于查看会话正在等待什么。
一个(阻塞的)会话等待某个东西的锁定,而该锁定又可能已被其他会话锁定(具有LOCK_TYPE
和LOCK_DURATION
),但是这里没有直接的“会话X等待会话Y”关系,这暗示着该锁定已经到位。
当多个会话都在等待相同的资源时,并且当该资源可用时(一个会话释放了元数据锁),尝试预期处理顺序(在我看来)是有风险的,并且应用程序逻辑不应依赖于此:据我所知,当前的实现确实是一个FIFO,但这可能随时更改,没有记录在案。
这里的合理性是服务器必须具有一定程度的自由度,以便例如出于性能原因而实施不同的调度策略是可行的。如果某种应用程序以某种方式“期望”给定的顺序,它将中断并阻止任何更改。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句