Mysql锁详解

行级锁和表级锁

  • 行级锁:开销大,锁的粒度小。 
  • 表级锁:开销小,锁的粒度大。

InnoDB同时支持行级锁和表级锁

共享锁(S)和排他锁(X) 

  • 共享锁:也称为读锁,允许多个事物读,但是不允许写 
  • 排他锁:也称为写锁,不允许读和写 

 

锁类型 共享锁 排他锁
共享锁 兼容 互斥
排他锁 互斥 互斥

 

意向共享锁(IS)和意向排他锁(IX)

  • 意向共享锁:事务在给数据行加行级共享锁之前,必须先取得该表的意向共享锁。
  • 意向排他锁:事务在给数据行加行级排他锁之前,必须先取得该表的意向排他锁。

主要作用:当表要变更结构时,要获取表的X锁,需要判断每行是否有排他锁,没有才能获取,效率比较低。于是引入了意向共享锁和意向排他锁。
表级排他锁和意向共享锁和意向排他锁是冲突的,这样就避免扫描每行数据

锁类型 共享锁 排他锁 意向共享锁 意向排他锁
共享锁 兼容 互斥 兼容 互斥
排他锁 互斥 互斥 互斥 互斥
意向共享锁 兼容 互斥 兼容 兼容
意向排他锁 互斥  互斥 兼容 兼容

 

行锁:

  • 记录锁(Record Lock)
  • 间隙锁(Gap Lock)
  • 临键锁(Next-Key Lock)

表结构:

CREATE TABLE `test` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) DEFAULT NULL,
  `age` bigint DEFAULT NULL,
  `idNum` varchar(100) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `test_unique_idNum` (`idNum`),
  KEY `test_age_IDX` (`age`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

查看隔离级别:

SELECT @@TRANSACTION_ISOLATION;  

 本人是REPEATABLE-READ 级别,可重复读

 把死锁日志监控打开,用于后面查看死锁日志

# 设置标准监控打开
set GLOBAL innodb_status_output=ON;
# 设置锁监控打开
set GLOBAL innodb_status_output_locks=ON;

主键上加锁:

事务1:

# 设置当前会话自动提交关闭
SET autocommit = OFF;

select * from test where id = 1 for update

 事务2:

# 设置当前会话自动提交关闭
SET autocommit = OFF;

select * from test where id = 1 for update

 执行事务2时死锁,查看死锁日志,如下:

show engine innodb status  

image

 可以看到事务1(事务ID:7988)加了2个锁

 1个是表级意向排他锁IX, 一个是行锁,主键索引上存在一个记录锁。

 非唯一索引加锁

  例子1: 加锁对象存在

   

SET autocommit = OFF;
select * from test where idNum = '1001' for update

 查看死锁日志:

image

 分别对应表级意向排他锁、基于idNum索引1001的锁,基于主键索引1的锁。

 

例子2:加锁对象不存在

SET autocommit = OFF;
select idNum from test where idNum = '1002' for update

查看死锁日志:

image

 可以看到只加了2个锁,一个是表级意向排他锁,一个是间隙锁。锁区间范围是(1001, 1005),防止其他数据插入

非唯一索引

事务1:

 

posted @ 2026-01-25 23:41  想养老看世界  阅读(17)  评论(0)    收藏  举报