我有一堆连接在事务中执行SELECT而一个执行DDL。 mysql手册非常清楚如何在事务中采用元数据锁:
为确保事务可序列化,服务器不得允许一个 session上执行数据定义语言(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顺序处理,但似乎并非如此。
是否有关于处理元数据等待队列的顺序的文档?
答案 0 :(得分:0)
试图重现此案,我阻止了会话B,然后阻止了会话C ... 请注意,如果会话B实际上在获取表上的元数据锁之前正在等待其他内容,则会话C没有理由等待。
已授予的元数据锁在表performance_schema
的{{1}}中可见,其中metadata_locks
为LOCK_STATUS
。
查看文档: https://dev.mysql.com/doc/refman/8.0/en/metadata-locks-table.html
这有助于查看哪个会话拥有哪个锁。
会话正在等待的元数据锁定在同一表中也可见,GRANTED
与LOCK_STATUS
一样。
这有助于查看会话正在等待什么。
(阻止的)会话等待某个内容的锁定,而该锁定又可能已被其他会话锁定(具有各种PENDING
和LOCK_TYPE
),但是没有直接的“会话X等待对于会话Y”的关系,则暗示已存在锁定。
当多个会话都在等待同一资源时,并且当该资源可用时(一个会话释放了元数据锁),试图预见处理顺序(在我看来)是有风险的,并且应用程序逻辑不应依赖关于这一点:据我所知,当前的实现确实是一个FIFO,但这可能随时更改,并且没有记录。
这里的合理性是服务器必须具有一定的自由度,以便例如出于性能原因而实施不同的调度策略是可行的。如果某种应用程序以某种方式“期望”给定的顺序,它将中断并阻止任何更改。