【Mysql中的锁机制二】
文章目录
- RC隔离级别下的锁竞争:
- 环境准备
- 测试CASE:
- CASE1:
- RR隔离级别的所竞争:
- 环境准备:
- 测试case
- CASE1:
- CASE2:
- CASE3:
- 如何找出阻塞的线程并kill掉
- 查看阻塞sql线程
- 找出阻塞的sql语句
RC隔离级别下的锁竞争:
环境准备
数据库下的mysql的隔离级别默认是REPEATABLE-READ,所以我们需要设置成RC隔离级别,执行下面的命令:
#设置隔离级别
SET GLOBAL TRANSACTION_ISOLATION='READ-COMMITTED';
#查询隔离级别
select @@TRANSACTION_ISOLATION;
创建一个测试表:
#创建表
CREATE TABLE `t` (
`id` int(11) NOT NULL,
`c` int(11) DEFAULT NULL,
`d` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `c` (`c`)
) ENGINE=InnoDB;
#插入数据
insert into t values
(0,0,0),
(5,5,5),
(10,10,10),
(15,15,15),
(20,20,20),
(25,25,25);
测试CASE:
CASE1:
开启三个事务,分别写入三条更新sql,来判断RC隔离级别下没有间隙锁和临建锁,只有行锁。
事务1
#开启事务
begin;
update t set d=d+1 where id>25;
#暂时不提交
事务2
update t set id=id+1 where id>25;
#被阻塞
事务3
update t set id=id+1 where id>26;
#执行成功
事务三执行成功说明,事务1没有间隙锁,
分析事务1和事务2的锁:
select * from sys.innodb_lock_waits\G;
下面的结果显示只有行锁没有间隙锁
RR隔离级别的所竞争:
环境准备:
查询当前myysql的隔离界别:
select @@transaction_isolation;
如果出现 REPEATABLE-READ就是在RR隔离级别下,如果没有出现执行下面的命令,设置RR隔离级别。
SET GLOBAL TRANSACTION_ISOLATION=REPEATABLE-READ;
创建一个测试表:
#创建表
CREATE TABLE `t` (
`id` int(11) NOT NULL,
`c` int(11) DEFAULT NULL,
`d` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `c` (`c`)
) ENGINE=InnoDB;
#插入数据
insert into t values
(0,0,0),
(5,5,5),
(10,10,10),
(15,15,15),
(20,20,20),
(25,25,25);
测试case
CASE1:
开启两个事务同时对一条已存在的数据进行更新,判断是否有锁机制:
事务1:
#开启事务1
begin;
update t set d=d+1 where id=5;
#暂时不提交
事务2
#开启事务2
update t set d=d+1 where id=5;
执行事务2时我们发现2被阻塞,证明事务1已经拿取到锁
证明是行锁:
我们执行select * from sys.innodb_lock_waits\G;
CASE2:
开启两个事务,一个对一条不存在的数据进行更新,另一个事务执行里这个id最近的两个范围内插入一条,id是这个范围内的数据,进行插入;
事务1
#开启事务
begin;
update t set d=d+1 where id=6;
#暂时别提交
事务2
insert into t values(6,6,6);
#被阻塞
怎么判断是间隙锁:
select * from sys.innodb_lock_waits\G;
从执行结果标红的看,此时被间隙锁所阻塞。
CASE3:
更新一个存在的id数据,插入一个id相邻的数据:
事务1
begin;
update t set d=d+1 where id=6;
#暂时不提交事务
事务2
insert into t values(7,7,7);
数据插入成功,就证明update获取到的是行锁,不影响插入的数据。
如何找出阻塞的线程并kill掉
查看阻塞sql线程
show processlist;
我们找到command 位query的,state为wait的线程。
找出阻塞的sql语句
1.找到对应的processlist_id对应的thread_id
select * from performance_schema.threads;
2.找到对应的thread_id
select * from performance_schema.events_statements_current;
找出对应的thread_id,以及对应的sql_text。
3. kill process_id将当前的阻塞线程杀掉。