全局锁
主要用在逻辑备份中,db引擎不支持事务的场景下。对于Innodb引擎,建议用single-transaction,视图形式备份,不影响业务;
表锁
一般在数据库引擎不支持行锁的时候,才会用到。
在mysql中,引入了MDL(metadata lock),对一个表做增删改查时,加MDL读锁;对表结构做变更时,加MDL写锁。
MDL 读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥,这个很好理解,可以保证表结构变更的安全性。
给一个表加字段,或修改字段,或加索引,需要扫描全表数据。(这个原理待了解清楚)。因此,表变更需要慎之又慎。
MDL锁使用过程中的隐患
session A启动一个事务,查询表T,则对表T加MDL读锁;
同时,session B要变更表T的结构,需要对表T加一个MDL写锁,但是A的事务未结束,锁不释放,会导致session B阻塞;
这时,session C,要查询表T,需要加MDL读锁,结果由于B还是阻塞,持有MDL写锁,则导致C查询阻塞,如果前端对该查询业务属高频查询,则会导致前端超时重试,从而导致数据库里可能被该查询的session爆满。
重要的事情再说一遍:事务中,MDL锁申请到后,不是语句执行完就释放,而是要等事务完成后,才释放。
安全变更表项
首先,要解决长事务,消灭长事务。
其次,如果要变更的表,是热点表,数据量不大,但是请求很频繁,该如何处理?根据前面描述的隐患中的原因:MDL写锁获取被阻塞。先解决这个问题,对该语句设定超时时间,超时后放弃修改。
行锁
即事务操作某行数据时,其他事务如果要操作,则会被阻塞。
两阶段锁:在一个事务中,到某个语句需要行锁时,才会为该语句加锁,但是锁资源的释放,则要等到事务完成后,才能释放。
行锁的使用,需要注意死锁问题,一方面使用mysql的检测工具,另一方面,在设计时,尽量规避该问题。