MySQL,作为广泛使用的开源关系数据库管理系统,提供了多种锁机制来满足不同场景下的需求
本文将深入探讨MySQL中锁表的用法,包括全局锁、表级锁和行级锁,并通过实例展示其实际应用
一、锁机制概述 锁是计算机协调多个进程或线程并发访问某一资源的机制
在数据库中,数据是需要争抢的共享资源,如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题
MySQL中的锁按照锁的粒度可以分为全局锁、表级锁和行级锁
二、全局锁 全局锁是对整个数据库实例加锁,加上全局锁后,整个数据库将处于只读状态,后续的DML(数据操纵语言)语句、DDL(数据定义语言)语句以及更新操作的事务提交语句都将被阻塞
全局锁的典型使用场景是做全库的数据备份,需要对所有的表进行锁定,从而获取一致性视图,保证数据的一致性和完整性
使用全局锁的方法如下: 1.锁定全局:FLUSH TABLES WITH READ LOCK; 2. 解除全局锁:UNLOCK TABLES; 数据备份示例: 1. 获取全局锁:FLUSH TABLES WITH READ LOCK; 2. 使用mysqldump工具做数据库的备份(在Linux终端中运行):`mysqldump -uroot -p123456 > /tmp/blog.sql`(注意:显式地在命令行中展现密码存在安全风险); 3.释放全局锁:UNLOCK TABLES; 使用全局锁造成的问题: 全局锁是一个比较重的操作,存在以下问题: - 如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停止
- 在InnoDB引擎中,可以在备份时加上`--single-transaction`参数来完成不加全局锁的一致性数据备份
三、表级锁 表级锁每次操作都会锁住整张表,锁定粒度大,发生锁冲突的概率最高,并发度最低
表级锁应用在MyISAM、InnoDB、BDB等存储引擎中
表级锁主要分为表锁、元数据锁(Meta Data Lock,MDL)和意向锁
表锁: 表锁分为表共享读锁(Read Lock,读锁)和表独占写锁(Write Lock,写锁)
- 读锁:允许其他事务读取该表,但不允许修改
如果一个事务已经获得了某个表的读锁,其他任何试图对该表进行写操作的事务将会被阻塞,直到持有读锁的事务释放锁
但读锁不会阻塞其他事务对同一表的读操作,意味着多个事务可以同时获取表锁的读锁
- 写锁:排他锁,不允许其他事务读取或修改该表
如果一个事务已经获得了某个表的写锁,其他任何试图对该表进行读或写操作的事务都会被阻塞,直到持有写锁的事务释放锁
使用表锁的语法: 1. 加锁:LOCK TABLES table_name【AS alias_name】 lock_type; 2.释放锁:UNLOCK TABLES; 示例: - 要对表user加写锁:`LOCK TABLES user WRITE;` 释放锁:UNLOCK TABLES; 元数据锁(MDL): 元数据锁的加锁过程是系统自动控制,无需显式使用,在访问一张表的时候会自动加上
元数据锁的主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作(为了避免DML语句和DDL语句之间的冲突,保证读写操作的正确性)
意向锁: 为了避免执行DML语句时加的行锁与加的表锁冲突,InnoDB引入了意向锁
意向锁使得表锁不用检查每行数据是否加锁,从而减少了取得表锁之前的检查
意向锁分为意向共享锁(IS锁)和意向排他锁(IX锁)
四、行级锁 行级锁每次操作锁住对应的行数据,避免了锁定整个表的低效性
行级锁可以并发地读/写单个行数据,提高了数据库的并发性能
行级锁分为共享锁和排他锁,分别用于读取和写入操作
使用行级锁的语法: 1.锁定行:SELECT ... FROM table_name WHERE ... FOR UPDATE; 2. 解除行锁:COMMIT; 示例: - 要对表user中的id为1的一行加排他锁:`SELECT - FROM user WHERE id=1 FOR UPDATE;` 提交事务以解除行锁:COMMIT; 行级锁还包括记录锁(Record Lock)、间隙锁(Gap Lock)和临键锁(Next-Key Lock)
记录锁:锁定索引记录
间隙锁:锁定索引记录之间的间隙,防止幻读
- 临键锁:InnoDB的默认锁机制,锁定索引记录及其前面的间隙
示例: - 锁定id在(3,7)之间的记录及其间隙:`SELECT FROM t5 WHERE id >3 AND id <7 FOR UPDATE;` 五、锁的选择与优化 锁的使用会降低数据库的并发性能,因此应该尽量避免过度使用锁
在实际应用中,应该根据具体情况选择合适的锁级别和锁定范围
- 全局锁:适用于全库备份等需要确保数据一致性的场景,但会阻塞所有写操作,影响业务运行
- 表级锁:适用于需要对整张表进行操作且对并发性能要求不高的场景
- 行级锁:适用于需要对表中的某几行进行修改且对并发性能要求较高的场景
此外,还可以通过优化SQL语句、调整事务隔离级别、使用合适的索引等方式来减少锁的使用和冲突
六、死锁与解锁 死锁是指两个或多个进程同时持有某些资源而互相等待对方释放资源的现象
在MySQL中,如果出现死锁现象,可以使用以下语句解锁:`KILL CONNECTION connection_id;`
其中,connection_id是被锁的连接的ID
可以使用以下命令查询锁定情况:`SHOW ENGINE INNODB STATUS;`
七、总结 MySQL提供了多种锁机制来满足不同场景下的需求
全局锁、表级锁和行级锁各有优缺点,应根据具体需求选择合适的锁级别和锁定范围
同时,还应注意优化SQL语句、调整事务隔离级别、使用合适的索引等方式来减少锁的使用和冲突,以提高数据库的并发性能和稳定性