MySQL中读写不互斥(前提是没有使用串行化隔离级别),但是写写操作要互斥才行,MySQL中使用锁机制来实现写写互斥。
按照锁的粒度可以分为:全局锁、表锁、行锁以及其他位于二者之间的间隙锁。
-
全局锁
锁定整个数据库,只允许读操作。后续 的DML的写语句,DDL语句,已经更新操作的事务提交语句都将被阻塞。
一般在备份数据库时使用
-- 设置全局锁 FLUSH TABLES WITH READ LOCK; -- 释放全局锁 UNLOCK TABLES;
数据库备份语句:
-- 设置全局锁 FLUSH TABLES WITH READ LOCK; -- 释放全局锁 UNLOCK TABLES;
在InnoDB引擎中,我们可以在备份时加上
--single-transaction
参数 来完成不加锁的一致性数据备份mysqldump --single-transaction -u账号 -p密码 库名 > E:/文件名.sql
-
表级锁
给整个表加锁,实现简单,资源消耗较少,MySQL大部分引擎支持。使用较多的MyISAM和InnoDB都支持表级锁。表级锁又分为表共享锁和表排他锁。
特点:开销小,加锁快;锁定粒度大,发出锁冲突的概率较高,并发度低,分两类:
①表共享锁(表共享读锁):当客户端1添加共享读锁,客户端1和客户端2只能读,不能进行写操作。
②表排他锁(表独占写锁):当客户端1添加独占写锁,客户端1能读也能写,客户端2不能读,也不能写。
-- 加锁 LOCK TABLES 表名 READ LOCK TABLES 表名 WRITE -- 释放锁 UNLOCK TABLES -- 断开连接也可以释放锁
MyISAM引擎只支持表锁
Innodb默认支持行锁
-
行级锁
行级锁是 MySQL 中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行锁能大大减少数据库操作的冲突。其加锁力度最小,但加锁的开销也是最大。
特点:开销大,加锁慢;锁定力度最小,放生锁冲突的概率最低,并发度最高。
行级锁又可以分为:
行锁(Record Lock)
-
共享锁(S锁)
共享锁(Shared Lock,S锁)允许事务读取数据,但不允许修改数据。当一个事务持有共享锁时,其他事务可以获得共享锁来读取该数据,但不能修改它。共享锁允许多个事务并发地读取数据,但不允许并发写入。
START TRANSACTION; SELECT * FROM stu WHERE age = 20 LOCK IN SHARE MODE; -- 其他事务可以读取,但不能修改该记录 COMMIT;
-
排他锁(X锁)
排他锁(Exclusive Lock,X锁)允许事务修改数据,同时会阻止其他事务对该数据进行任何类型的锁定(无论是读锁还是写锁)。排他锁在事务执行过程中会完全控制锁定的数据行,其他事务无法在此期间对其进行操作。
START TRANSACTION; SELECT * FROM stu WHERE id = 1 FOR UPDATE; -- 其他事务不能读取或修改该记录,直到当前事务提交或回滚 COMMIT;
间隙锁(Gap Lock)
间隙锁是 InnoDB 为了避免幻读而引入的一种锁。它锁定的是索引中的空隙,而不是具体的行数据。间隙锁确保在锁定的范围内,其他事务不能插入新的数据行,从而避免幻读现象的发生。
START TRANSACTION; SELECT * FROM stu WHERE age > 20 FOR UPDATE; -- 会在索引的"年龄 > 20"的范围内加锁,防止其他事务插入数据 COMMIT;
临键锁(Next-Key Lock)
临键锁是InnoDB的一种组合锁,实际上是行锁与间隙锁的结合体。临键锁会同时锁定数据行和数据行前后的间隙,以保证读取数据的一致性并防止其他事务插入数据,避免了“幻读”现象。
START TRANSACTION; SELECT * FROM stu WHERE salary BETWEEN 3000 AND 5000 FOR UPDATE; -- 会锁住所有符合条件的行和它们之间的空隙 COMMIT;
-