全局锁和表锁学习笔记

277 阅读3分钟

Mysql锁概览

数据库锁:当处理并发问题时候,数据库需要合理地控制资源的访问规则,而锁就是用来实现这些访问规则的重要数据结构。 加锁的范围:全局锁,表级锁,行锁。

全局锁

对数据库实例加锁,Flush tables with read lock (FTWRL),unlock tables解除。整个数据库只读,其他线程不能增删改,定义(建表,修改结构),更新事务,

场景:全库逻辑备份。

缺点:主库备份期间,不能执行更新,业务停摆。从库备份,备份期间不能执行主库同步来的binlog,导致主从延迟。

但是不加锁会导致数据出现不一致的情况

可重复读级别开启下一个事务可以拿到一致性视图,但是MyISAM引擎不支持,InnoDB支持。

set global readonly=true,全库只读,但是不建议使用。其一是有些系统中,readonly值会被用来做其他逻辑,比如判断主库还是被库,因此,修改global变量的方式影响面大。而是异常处理机制有差异,执行FTWRL后,由于客户端发生异常断开后,Mysql会自动释放全局锁,整个库可以回到正常更新状态,readonly发生异常,数据库保持不变,这样会使数据库长期处于不可写状态,风险高.

全局锁加上后,不只不能增删改数据(DML),加字段等修改表结构(DDL)也不允许

表级锁

分为表锁和元数据锁(meta data lock, MDL) 表锁语法是lock tables...read/write ,使用unlock tables可以主动释放锁,在客户端断开时也会自动释放。lock tables除了限制别的线程读写,也限定了本线程接下来的操作对象。

lock tables t1 read, t2 write:限制其他线程写t1,读写t2(阻塞该语句),本线程在执行unlock tables前,页只能读t1,读写t2.

MDL锁则不需要显式使用,访问一个表自动添加,保证读写正确性。例如果遍历一个表的数据,另一个线程在此期间对表做了变更,删除一列,结构变化,导致错误。

MDL是在MySql5.5版本后引入的,对表crud,加MDL读锁,对表结构做变更,加MDL写锁。加读锁所有线程可以正常读取元数据,不影响crud,不能修改表结构,即允许DML,阻塞DDL。加MDL写锁,阻塞其他线程DML与DDL。

但是有以下问题,如果按顺序有四个线程,第一个线程上读锁,第二个线程也是读锁,不会被影响,但是第三个线程改变表结构,被阻塞,后面再有申请MDL读锁的请求会被第三个线程阻塞,等于这个表现在完全不能读写。如果这个表查询频繁,客户端有重试机制,不停再请求,这个库的线程就会爆满。

因此要解决长事务,事务不提交,会占用MDL锁,如果DDL变更的表刚好有长事务执行,要么暂停DDL,要么kill这个事务。但是如果事务频繁,kill不一定管用,因为新很快就来,可以设置等待时间,在指定时间内拿到MDL写锁,拿不到不要阻塞后面语句,可以先放弃,重复命令。