MySQL根据加锁的范围,mysql锁大致可分为全局锁,表锁,行锁
全局锁
全局锁就是对整个数据库实例加锁,可以通过flush table with read lock(ftwrl)实现加全局锁。加锁后,其他线程的ddl,dml操作将被阻塞。
全局锁最典型的使用场景是全库逻辑备份。
设置全局锁风险:
如果在主库上设置,则加锁期间所有dml,ddl操作均不能执行,业务处于停滞状态
如果在从库上设置,则加锁期间同步过来的binlog均不能apply,复制延迟不断增大
官方的逻辑备份工具是mysqldump,在全库备份时会为了保证一致的逻辑备份时间点,会设置全局锁。后续可以通过--single-transaction参数避免设置全局锁。会在数据导出之前开启一个事务来保证一致性视图,并通过mvcc的支持,保证期间数据可以正常更新。当然该参数仅对支持事务的引擎有效。
那么ftwrl与set global read_only=true的区别是?
在某些系统中,read_only会被作为判断主库或从库的依据之一,因此修改global参数的影响面更大。
在异常处理机制上有差异。执行ftwrl命令的客户端如果异常断开,mysql会自动释放全局锁,数据库会回到可以正常更新的状态。而设置read_only=true,即使客户端异常断开,数据库仍然处于只读模式,会导致整个库长期处于不可写状态。
表级锁
mysql表级锁分为两种,表锁和元数据锁(MDL meta data lock)
表锁
表锁的语法是lock tables read/write。与ftwrl类似。可以用unlock tables解锁也可以在客户端断开时自动释放锁。需要注意的是lock tables语法除了限制别的线程读写外,也限制了本线程接下来的操作。
元数据锁
MDL锁不需要显式的使用,在访问一个表的时候会自动加上。MDL锁的作用是防止DDL和DML并发的冲突,保证读写的正确性。防止正在读写某张表时,表结构被另一个线程变更。
当对表进行增删改查操作时,加MDL读锁。当对表进行表结构变更操作时,加MDL写锁。
读锁之间不互斥,可以多个线程同时对一张表增删改查。
读写锁之间,写锁之间互斥,用来保证变更表结构操作的安全性。
意向锁
为了支持行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁。(可以简单理解为支持并发DDL和DML互不冲突)
意向共享锁(IS)
事务打算给数据行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
意向排他锁(IX)
事务打算给数据行加排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
行锁
行锁应用于innodb存储引擎,行锁主要分为共享锁(S)和排他锁(X)。
共享锁
当一个事务对某行或某些行加了共享锁,在该事务结束期间,其他事务对其只能进行读操作,不能进行写操作。
用法:SELECT `id` FROM table WHERE id in(1,2) LOCK IN SHARE MODE
排他锁
当一个事务对某行或某些行加了排他锁,在该事务结束期间,其他事务不能对其加任何锁。
用法:SELECT `id` FROM mk_user WHERE id=1 FOR UPDATE
PS: