MySQL的锁根据加锁的范围可以分为全局锁表锁行锁

    全局锁 (关键词:ftwrl , mysqldump, readonly)
    就是锁住整个库,使用flush table with read lock (ftwrl)可以使整个库处于只读状态,使用场景是全库备份数据的时候。但是使用这个命令的问题是:
    1 当在主库执行这个语句的时候,主业的业务基本上就得停摆,会收到影响。
    2 当在从库上执行这个语句的时候,从库就无法执行从主库同步过来的binlog
    mysql自带的mysqldump会使用 -single-transaction,在导数据之前利用MVCC拿到一个一致性视图,这样既保证了数据的一致性,又不会对数据库的业务造成影响。有了mysqldump为啥还需要ftwrl, 因为有的存储引擎不支持事务,只能使用ftwrl。
    还有一个命令 set global readonly=true;也可以使整个库处于可读状态,但不推荐使用,因为
    1 在有些系统中readonly可能用来做其他判断,比如判断一个库是主库还是从库,如果修改这个,影响范围就比较大。
    2 ftwrl 会在客户端异常断开的时候,数据库自动释放全局锁,而readonly在客户端断开后,会一直保持只读状态,会影响到整个库的使用。

    表级锁
    表级锁分为表锁和元数据锁(metadata lock)
    表锁要使用命令 lock tables …. read/write; 与ftwrl类似,当客户的断开连接的时候,会自动释放锁。但是这个操作除了限制别的线程对表的操作外,也会限制本线程对表的操作。例如 lock tables A read, B write; 其他线程只能对A表读,B表无法读写。在当前线程执行unlock tables之前,也只能对A表读,是不允许写的,对B表是可以读写的。
    有了更细粒度的行锁后,一般不使用lock tables来操作。
    还有一类表级锁是元数据锁,就是锁表结构的,不需要显示使用,也无法干预,会在使用表的时候自动加锁,这样能保证在是用表期间保证表结构的完整性,MDL锁是为了使DDL语句和DML语句互斥,就是查询,更新那些语句和对表结构操作的互斥。如果A线程正在读取数据,B线程增加或则删除了一个表字段,这比幻读还严重,简直就是人格分裂读。
    MDL是MySQL5.5版本引入的,在读取数据的时候会申请MDL读锁,写数据的时候会申请MDL写锁,读锁和写锁,读锁和写锁,写锁和写锁是互斥的。申请MDL的操作会形成一个队列,写锁优先级高于读锁,一旦写锁被阻塞了,后续的其他的线程的操作也会被阻塞,导致影响业务
    如果不得不加字段,1是先解决长事务,因为长事务会一直占着MDL锁,
    2是用超时等待,MariaDB 已经合并了 AliSQL 的这个功能,例如,

    1. ALTER TABLE tbl_name NOWAIT add column ...
    2. ALTER TABLE tbl_name WAIT N add column ...

    行锁
    行锁就是对一条记录的锁,当一个事务要更新一条记录时,数据库会对这个操作加锁,如果有别的事务也要更新这条记录,则需要等待上一个事务释放锁。
    锁的释放不是在更新完成后,而是在事务提交的时候,所以影响业务的语句尽量往后放。
    行锁的使用过程中容易出现死锁,如果出现死锁
    一种方法是等待超时释放,通过innodb_lock_wait_timeout可以设置等待锁的时间,但是太长和太短都不合适,太长会影响业务,太短无法判断是不是死锁。所以一般推荐使用第二种方式。
    二是开启死锁检测,设置innodb_deadlock_detect 为on可以开启,但是检测比较相当耗费性能。那一种思路是关闭死锁检测,但是会有死锁产生,可能会有很多超时业务。二是控制并发,可以考虑使用中间件,或者如果有能力修改源码,可以直接修改MySQL。