本文共 2012 字,大约阅读时间需要 6 分钟。
在并发场景下,锁是一种保证线程安全的方式。对于 MySQL 数据库,尤其是在并发环境下,当多个事务同时操作同一数据时,可能会出现脏读、不可重复读、幻读等事务并发问题。为了解决这些问题,MySQL 采用了不同的锁机制来确保数据的一致性和有效性。
MySQL 的默认事务隔离级别是可重复读(RR),在这个隔离级别下,读操作依靠快照读(基于 MVCC 实现)和当前读(加锁实现)来避免并发问题,而写操作则通过加锁的方式来避免冲突。因此,MySQL 需要锁来防止事务并发问题,保证数据的安全性和一致性。
InnoDB 是 MySQL 的默认存储引擎,支持行级锁和表级锁。以下是 InnoDB 的锁机制详细解析。
要查看事务加锁情况,可以通过以下方式操作:
关闭自动提交:
SET @@autocommit = 0;
查看当前状态:
SELECT @@autocommit;
每次操作前使用 begin;
或 start transaction;
开启事务,执行后使用 commit;
手动提交事务。
使用以下命令查看加锁情况:
SELECT * FROM performance_schema.data_locks;
关注字段:
OBJECT_NAME
:被锁的表名。INDEX_NAME
:对应的锁索引名。LOCK_TYPE
:锁类型(表级锁或行级锁)。LOCK_MODE
:锁模式(如 S 锁或 X 锁)。LOCK_STATUS
:锁状态(GRANTED 或 WAITING)。LOCK_DATA
:锁的相关数据(如索引值)。InnoDB 的行级锁分为共享锁(S 锁)和排他锁(X 锁)。根据锁模式进一步划分为记录锁、间隙锁和临键锁。
共享锁(S 锁):用于读取记录,允许其他事务获取共享锁,但不允许其他事务获取排他锁。常通过 SELECT ... lock in share mode;
实现。例如:
SELECT * FROM products WHERE id = 1 lock in share mode;
排他锁(X 锁):用于修改记录,阻止其他事务的读或写操作。常通过 SELECT ... for update;
、UPDATE
、DELETE
等语句实现。例如:
SELECT * FROM products WHERE id = 1 for update;UPDATE products SET stock = 99 WHERE id = 1;
在可重复读(RR)隔离级别下,为了防止幻读,InnoDB 使用记录锁、间隙锁和临键锁。
记录锁:锁住一条记录,常用于主键等值查询且记录存在的情况。
例如:SELECT * FROM products WHERE id = 1 for update;
查看锁情况:
SELECT * FROM performance_schema.data_locks;
间隙锁:锁住一个区间,常用于主键等值查询且记录不存在的情况。
例如:SELECT * FROM products WHERE id = 3 for update;
查看锁情况:
SELECT * FROM performance_schema.data_locks;
临键锁:由记录锁和间隙锁组成,锁住一个左开右闭区间,常用于普通索引等值查询且记录存在的情况。
例如:SELECT * FROM products WHERE price = 799.99 for update;
查看锁情况:
SELECT * FROM performance_schema.data_locks;
锁兼容关系:
InnoDB 也支持表级锁,常用于全表操作:
共享型表锁(S 表锁):允许其他事务读取表中的数据,但不允许修改。
LOCK TABLES products READ;
排他型表锁(X 表锁):阻止其他事务对表进行读或写操作。
LOCK TABLES products WRITE;
意向锁:用于加快判断表中记录是否被锁。
SHOW VARIABLES LIKE 'innodb_%lock_mode%';
自增锁用于主键自增功能,确保并发插入时的数据一致性。
CREATE TABLE products ( id INT AUTO_INCREMENT PRIMARY KEY);
通过以上锁机制,InnoDB 保证了事务的安全性和数据的一致性。在实际应用中,应根据业务需求合理选择锁类型,避免全表扫描等性能问题。
转载地址:http://rtdfk.baihongyu.com/