1、背景
在我们系统中有一张表它的查询概率非常高。最近有个需求,需要对这个表增加一个字段,然而在增加字段的时候发现系统中有多个业务出现了超时操作,那么这个是什么原因导致的呢?经过查阅资料发现是数据库的MDL锁+事务导致的。
2、什么是MDL锁
MDL锁属于表级别的元数据锁。表级别锁分为数据锁和元数据锁,通常我们说的加锁一般指的是加的数据锁。跟数据锁一样,元数据锁也分读锁和读写锁。
MDL不需要显示使用,在进行表操作时会自动加上。当对表进行增删改查时,会自动加上MDL读锁;当要对表进行加减字段的结构修改时,会自动加上MDL写锁。
- 读锁不互斥,意味着可以多个线程同时对一张表进行增删改查的操作。
- 写锁独占,进行结构修改前,要先等待其他所有的MDL锁释放了才能获取到MDL写锁。获取到写锁后,在写锁释放前,其他线程无法获取到MDL读锁和写锁。也就是说,修改一个表的结构过程中,会阻塞其他线程对表的操作。
3、MDL锁的必要性
MDL锁的存在,其实是为了保证数据的一致性。想象一下,假如没有MDL锁,一个查询在遍历表数据的过程中,另外一个线程执行了ALTER TABLE t DELETE COLUMN 'col_1'
把col_1
这一列删掉了,那查询结果就乱了,结果中是否应该有这一列数据?
4、举例说明
✅ :表示正常往下执行
❌ :表示卡住了,即无法往下执行。
事物一 | 事物二 | 事物三 |
start transaction;✅ 1️⃣ | ||
select * from customer;✅2️⃣ | alter table customer add column_4 int null;❌3️⃣ | |
select * from customer;❌4️⃣ | ||
commit;✅5️⃣ | ✅6️⃣ | ✅7️⃣ |
解释:
步骤 1️⃣2️⃣正常执行。执行步骤2️⃣时,会申请表customer
的MDL的SHARED_READ锁
。
步骤3️⃣会卡住,因为此时会申请表customer
的MDL的EXCLUSIVE锁
,但是事物一的事物没有提交,此时是无法申请到EXCLUSIVE
锁,因为它们是互斥的。
步骤4️⃣也会卡住,因为EXCLUSIVE
锁和SHARE_READ
锁是互斥的,且EXCLUSIVE
锁的优先级更高,所以步骤4️⃣也会卡住。
步骤5️⃣事物提交,释放表的SHARE_READ
锁,之后就可以执行6️⃣和7️⃣的操作了。
如果先执行事务二,在执行事务三,则是可以成功的,因为alter数据ddl语句,和事物无关。