一、全局锁
全局锁是对整个数据库实例进行加锁。
给数据库实例加上全局锁的方法是:
使用命令 Flush tables with read lock (FTWRL)
加锁的后,以下的程序会被阻塞:
数据更新语句(增删查改)、数据定义语句(表的建设,表结构的修改)、更新类事务的提交语句。
什么时候使用全局锁?
做数据库的逻辑备份。
为什么备份需要加锁呢?
不加锁,备份的库无法得到一个逻辑时间点上的数据库,这个逻辑事务不具有一致性。(大概的意思是:数据库里面有多个表格是互相关联的。如果不加锁,可能的后果是某些表格上面的数据更新了,而与之相关的表格上面的数据并没有更新)
官方自带的逻辑备份的工具是 mysqldump ,当 mysqldump 使用参数 –single-transaction 能够实现一致性视图(事务执行过程中所看到的视图和事务启动时候所看到的数据库视图是一致的)。但是这个只适用于所有的表都使用支持事务的引擎。
为什么有了 mysqldump 依然需要 FTWRL 呢?
因为不是所有的引擎都支持一致性读,比如对于 MyISAM 这种不支持事务的引擎,不支持一致性,所以必须使用 FTWRL。(大概的意思是,不是所有的引擎都能够使用 工具A,所以必须使用工具B 来达到同样的目的)
为什么不通过使用 set global readonly = true 的方式来实现整个数据库只读呢?
原因有二:
1)readonly 的值可能会用作于其他的逻辑。
2)异常处理机制上有差异。
如果将 readonly 设置为 true 之后系统异常终止,再次启动的时候依然保持着 readonly 的状态。数据库会长时间的处于只读的状态。(接班的程序员不一定知道之前发生了啥)
表级锁:
有两种表级锁:表锁和元数据
1)一种表锁
表锁通过 lock tables …read/write 加锁,通过 unlock tables 释放锁
这种加锁方式会限制其他线程的操作,也会限制当前进程接下来的操作。
当前进程对某个表加锁之后,只能执行锁所限定的动作,不能访问其他的表。
2)另一个种表锁 MDL
这种表锁不需要显示加上。
做增删查改的时候,加上读锁;
改动表格的结构的时候,加上写锁。
读锁和读锁之间不互斥,因此可以多个线程可以同时对表格进行增删查改。
读写锁和写锁之间互斥,多个线程之间不能对表格进行表格结构的变动。
事务中的 MDL 锁,在语句执行的时候开始执行,但是语句结束之后不会马上释放,得等到整个事务提交之后才会释放。
如果一个进程一直没有释放锁,会造成后面申请锁的事务阻塞,用户端在超时之后可能会重新申请事务。很容易造成多个进程导致爆满。
如何安全的给小表加上字段?
1)kill 掉长事务。防止长事务对后面的进程造成阻塞。
2)设定等待时间,如果等待时间之内没有拿到锁,就放弃申请,不要阻塞后面的事务。