ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

锁机制-innodb锁模式

2022-07-23 19:33:40  阅读:201  来源: 互联网

标签:name update 模式 linelock 会话 innodb 机制 where id


目录

innodb的表级锁模式

innodb也支持表锁,只能手动加表锁,表锁命令同样适用于innodb,规则和myisam的规则一致

image

image

innodb的行级锁模式

InnoDB存储引擎默认使用行锁,支持表级锁。

默认情况下:不会自动加读锁,会自动加写锁。

支持事务

行锁解锁方式

开启autocommit后,手动 或 自动加的锁 在SQL执行完后 都会自动释放。
关闭autocommit后,手动 或 自动加的锁 都需要通过事务解锁。

关闭自动commit

--mysql默认自动commit; oracle默认不会自动commit ;
为了方便研究行锁,暂时将自动commit关闭,以后需要通过commit

准备数据

create table linelock
(
id int(5) primary key auto_increment,
name varchar(20)
)engine=innodb ;

insert into linelock(name) values ('1');
insert into linelock(name) values ('2');
insert into linelock(name) values ('3');
insert into linelock(name) values ('4');
insert into linelock(name) values ('5');

commit ;

写锁

操作同一条数据

两个会话update或delete同一条数据(即便是第一个会话刚插入还没有来得及提交的数据)

会话0:
delete from linelock where id = 3;

会话0:对其他行、其他表的操作

image

小结:
会话0对某条数据加锁后,该会话可以在行锁未释放的情况下对其他行、其他表继续操作,继续加锁。

会话1
update linelock set name='ax' where id = 3; -- 阻塞

select * from linelock where id = 3; -- innodb默认不加锁 执行成功

select * from linelock where id = 3 lock in share mode;
select * from linelock where id = 3 for update;

image

小结:
如果会话0对某条数据a进行DML操作,则其他会话对数据a进行操作必须等待会话0释放行锁(结束事务 commit/rollback)。(研究时:关闭了自动commit的情况下)

操作不同数据

会话1:写操作,不同的数据
update linelock set name='5x' where id = 5;  -- 执行成功

小结:
行锁,一次锁一行数据;因此如果操作的是不同数据,则不干扰。

间隙锁

行锁的一种特殊情况:间隙锁:值在范围内,但却不存在

update linelock set name = 'x' where id >1 and id<9 ; -- 此时linelock表中没有id=7的数据

在此where范围中,没有 id=7的数据,则id=7的数据成为间隙。Mysql会自动给间隙加锁->间隙锁。即本题会自动给id=7的数据加间隙锁(行锁)。

行锁:如果有where,则实际加锁的范围就是where后面的范围(不是实际的值)

死锁

事务1和事务2互相持有对方需要的锁而不释放,造成死锁的情况

事务1:update linelock set name='zs' where id=4;
事务2:update linelock set name='zs1' where id=5;

事务1:update linelock set name='ls' where id=5; -- 阻塞
事务2:update linelock set name='ls1' where id=4; -- 报错(死锁),事务2被干掉(前面执行的update5也被撤销),同时事务1的update5执行成功。

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
image

当事务1update4的时候,事务2update5,但是由于innodb是行锁,没有问题,可以执行

继续:事务1 update5 的时候,由于5被事务2锁着,没有释放,会被阻塞,等待事务2提交

然后事务2继续update4,报错:4被事务1锁着呢,同时事务1要操作5,但是5被事务2锁着呢,就遭成了死锁

对query语句加锁

innodb 默认不加读锁,如果需要更改 需要修改隔离级别,默认 隔离级别为 可重复读。

能否手动加锁?

读锁(共享锁、S锁):select ... lock in share mode;

写锁(排它锁、X锁):select ... for update;

手动加读锁

会话1:select * from linelock where id = 5 lock in share mode;
会话2:update linelock set name='zzz2' where id = 5; -- 阻塞
会话3:select * from linelock where id = 5 lock in share mode;

image

手动加写锁

会话1:select * from linelock where id=2 for update;
会话2:
select * from linelock where id = 2; -- 默认 不加锁
select * from linelock where id = 2 lock in share mode; -- 阻塞
select * from linelock where id = 2 for update; -- 阻塞

会话3:
update linelock set name = '222' where id = 2; -- 阻塞

image

行锁会转为表锁(什么情况下 行锁会锁全表)

1.如果 没有索引索引失效,则行锁会转为表锁

show index from linelock ;
alter table linelock add index idx_linelock_name(name);

-- 索引未失效
会话0:写操作
update linelock set name = 'ai' where name = '3';
会话1: 写操作,不同的数据
update linelock set name = 'diX' where name = '4' ;

-- 索引失效
会话0:写操作
update linelock set name = 'ai' where name = 3 ;
会话1:写操作,不同的数据
update linelock set name = 'aiX' where name = 4;
-- 可以发现数据被阻塞了(加锁)

原因: 如果索引类 发生了类型转换,则索引失效。因此此次操作,会从行锁转为表锁。

2.查询表中所有数据,或者 删除所有数据也都会锁全表

如果 select * from linelock 后面 不添加where条件,则转为表锁。

会话0:select * from linelock for update;

会话1:select * from linelock; -- 正常执行
delete from linelock where id =1; -- 阻塞

标签:name,update,模式,linelock,会话,innodb,机制,where,id
来源: https://www.cnblogs.com/jiyuchen1/p/16507886.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有