InnoDB行锁升级表锁(简单易懂)

目录

1、InnoDB行锁的实现方式

2、案例分析

2.1 对没有索引的数据加锁(行锁升级)

2.2 对有索引的数据加锁(行锁) 

2.3 索引失效-导致锁升级

3、案例分析总结


1、InnoDB行锁的实现方式

        通过给索引上的索引项加锁来实现的,也就意味着:只有通过索引条件检索数据,InnoDB才会使用行级锁

2、案例分析

CREATE TABLE `account` (
  `id` int(32) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `balance` int(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

INSERT INTO `account`(`id`, `name`, `balance`) VALUES (1, 'lilei', 800);
INSERT INTO `account`(`id`, `name`, `balance`) VALUES (2, 'hanmei', 16000);
INSERT INTO `account`(`id`, `name`, `balance`) VALUES (3, 'lucy', 2400);
INSERT INTO `account`(`id`, `name`, `balance`) VALUES (4, 'lily', 700);

2.1 对没有索引的数据加锁(行锁升级)

1、session 1(客户端A) 开启一个事务,并且对一条数据做不是索引条件的修改操作

-- session 1(客户端A)
-- 开启事务
begin;
-- 修改条件没有索引
 UPDATE account set name = 'lilei111' where name = 'lilei';


2、session 2(客户端B)对该表的另一条数据进行修改,不管是否修改同一数据行都会阻塞(证明上一步使用了表锁)

-- session 2
-- 非索引条件修改
UPDATE account set name = 'hanmei123' where name = 'hanmei';
-- 索引条件修改
UPDATE account set name = 'hanmei123' where id = 2;


3、session 1(客户端A)commit或者rollback后session 2(客户端B)会解除阻塞

总结:

        也就是在INNODB加行锁的时候不仅会将该行数据进行加锁,还会将在此过程中扫描过的数据进行额外的加锁,所以如果MYSQL在找到目标数据的时候进行的是全表扫描,那么实际上就不是行锁了,而是直接将整个表给锁住了,如果是通过索引的方式确定到目标上锁的行数据,那么只会给目标数据进行上锁(因为如果使用索引查找是不用进行全表的数据遍历的)。

2.2 对有索引的数据加锁(行锁) 

1、session 1(客户端A)开启事务,然后通过索引修改数据(id是索引)

-- session 1

begin;
UPDATE account set name = 'lilei222' where id = 1;


 2、session 2(客户端B)根据其他id修改--可以提交(证明操作1是行锁)

--session 2
-- 索引条件修改
UPDATE account set name = 'hanmei123' where id = 2;

 


3、session 2(客户端B) 根据非索引字段修改其他数据行--发生锁冲突(证明该操作发生表锁,与操作1的行锁产生了锁冲突)

-- session 2
-- 非索引条件修改
UPDATE account set name = 'hanmei123-session 2' where name = 'hanmei123';

 


4、session 1 提交事务,创建索引后继续开启事务修改数据,并作操作1的动作

-- session 1 先提交上面的事务,可以后面创建索引
commit;
-- 创建索引
alter table account add index idx_balance(balance);

-- 开始事务,继续操作1的事务
begin;
UPDATE account set name = 'lilei222' where id = 1;

5、session 3(客户端C) 根据其他索引字段修改(条件没有冲突的数据行-可以提交)

-- session 3
-- 其他索引条件修改(没有冲突的数据行)
UPDATE account set name = 'hanmei123-session 3' where balance = 16000;

 


6、session 3 (客户端C)根据其他索引字段修改(条件有冲突的数据行-阻塞)

-- session 3
-- 其他索引条件修改(有冲突的数据行)
UPDATE account set name = 'lilei111-session 3' where balance = 800;

 

2.3 索引失效-导致锁升级

先将name修改为数字

 1、session 1(客户端A) 添加name索引,根据该索引进行修改,但是使用隐形类型转换手段导致该索引失效

-- session 1
-- 创建索引
alter table account add index idx_name(name);
-- 开启事务 

begin;
 -- 因为name是字符串,条件值为int导致所有失效

UPDATE account set name = 'lilei222-session 1' where name = 111;

 


2、session 2(客户端B)修改其他数据行,但是依然阻塞-锁升级,说明操作1升级到了表锁

-- session 2
UPDATE account set name = 'hanmei123-session 2' where name = 222;

 

3、案例分析总结

        如果想要保证行锁不升级为表锁,那么就需要在筛选字段(where后面的字段)上保证已经建立了索引,这里还需要保证索引是有效的,如果索引因为某些原因失效了,那么还是会导致全表扫描,那么依旧会升级为表锁。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郭吱吱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值