InnoDB事务与锁

InnoDB事务与锁

话不多说,直接上知识点:

事务

特性
1、原子性(Atomicity)
2、一致性(Consistency)
3、隔离性(Isolation)
4、持久性(Durability)
InnoDB中引擎对隔离级别的支持

事务隔离级别脏读不可重复读幻读
读未提交(Read Uncommitted)可能可能可能
读已经提交(Read Committed)不可能可能可能
可重复读(Repeatable Read)不可能不可能对InnoDB不可能
串行化(Serilalizable)不可能不可能不可能

为什么InnoDB不可能?请继续看(记得打开自己的mysql工具实际操作一波

锁是用于管理不同事务对共享资源的并发访问
行锁VS表锁
锁定粒度:行锁<表锁
加锁效率:行锁>表锁
概率冲突:行锁<表锁
并发性能:行锁>表锁
InnoDB支持行锁和表锁(特殊的行锁 )

InnoDB锁类型

在这里插入图片描述

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

共享锁: 读锁,S锁。多个事务对同一数据都可以访问,共享一把锁,但是只能读不能改
加锁方式: select * from sku where id =1 LOCK IN SHARE MODE;
排他锁: 写锁,X锁。不与其他锁共存,如果一个事务获取了该行的排他锁,则其他事务不能再获取该行的锁(S锁或X锁),只有此事务可以进行读取和修改。那其他事务一定不能读吗?(不一定,可进行快照读)
加锁方式:delete/insert/update默认加x锁。
select * from sku where id = 1 FOR UPDATE;

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

意向共享锁: 事务准备给数据行加S锁,加之前必须获得IS锁,锁之间可兼容。
意向排他锁: 事务准备给数据行加X锁,加之前必须获得IX锁,锁之间可兼容.
加锁方式:InnoDB在数据操作前自动加的,不需要用户干预。
那有什么意义:当事务想去锁表,先去判断是否该锁已经存在,如果存在则快速返回不能锁表。
满足了事务隔离性

临键锁&间隙锁&记录锁

临键锁: RR级别。锁记录+区间**(左开右闭)**
按照索引检索,范围查找(bewteen, < ,>)有数据命中
(-∞,1],(1,4],(4,7],(7,10],(10,+∞)
在这里插入图片描述
select * from tb where id >5 and id <9 for update;
锁住:(4,7],(7,10]

间隙锁: RR级别。 锁住索引不存在的区间**(左开右开)**
临键锁记录不存在退化成间隙锁
(-∞,1),(1,4),(4,7),(7,10),(10,+∞)
在这里插入图片描述
select * from tb where id >4 and id < 6 for update;
select * from tb where id = 6 for update;
锁住:(4,7)
select * from tb where id > 30 for update;
锁住 : (10,+∞)
记录锁: 按照唯一性(主键或者唯一)索引检索。锁住具体的索引项
如何避免脏读?
更新增加X锁,防止其他事务读或者写

-- --事务1 解决脏读 
START TRANSACTION;
select * from user where id = 1;
COMMIT;
ROLLBACK;
-- 事务2 解决脏读
START TRANSACTION;
update user set age = 16 where id = 1;  -- 加X锁 防止其他事务读或者写
COMMIT;
ROLLBACK;

如何避免不可重复读?
查询加S锁,防止其他事务update

--  事务1 解决不可重复读   
START TRANSACTION;
select * from user where id = 1 ;  -- 加S锁   结果??
COMMIT;
ROLLBACK;
-- 事务2 解决不可重复读(读取数据不允许其他事务进行update)
update user set age = 20 where id = 1; 

如何避免幻读?
临键锁,防止其他事务insert/delete

-- 事务1  解决幻读
START TRANSACTION;
select * from user where  id >0;  
COMMIT;
ROLLBACK;
-- 事务2 解决幻读(读取数据不允许其他事务进行insert/delete)
START TRANSACTION;
insert into user  values(2,'Two',22);
COMMIT;
ROLLBACK;

MVCC

Multi-Version Concurrency Control 多版本并发控制,通过在每行记录后面保存两个隐藏的列来实现的。
insert
当前版本号作为数据行版本号
delete
当前版本号作为行删除版本号
update
当前版本号作为数据行版本号,同时保持当前版本号作为原来的行的删除版本号
select
1 、查询小于等于当前事务版本号
2、 要么删除版本号为null ,
要么大于当前版本号
只适用于RR、RC级别
如图示:后面两隐藏列实际中并不可见。
在这里插入图片描述
举个例子:(最好实际跑一下)

insert into  mvccuser(name,age) value ('One',18); 
insert into  mvccuser(name,age) value ('Two',20);
-- 事务1
START TRANSACTION;              -- 1
select * from  mvccuser;        -- 2
COMMIT;
ROLLBACK;
-- 事务2
START TRANSACTION;                                -- 3
update mvccuser set age = 28 where id = 1;        -- 4 
COMMIT;
ROLLBACK;

执行顺序:12342
执行前:
在这执行里插入图片描述
执行12,此时txid=2时,查找结果:

idnameage
1One18
2Two20

执行3、4,此时txid=3,此时表结果:
在这里插入图片描述
再执行2,此时txid=2,查找结果:

idnameage
1One18
2Two20

执行顺序:3412
执行34,此时txid=2,结果:
在这里插入图片描述
再执行12此时txid=3,再得到结果之前我们先猜测一下结果:
根据mvcc的select规则查询结果,应该是:

idnameage
1One28
2Two20

然而实际结果确是:

idnameage
1One18
2Two20

为什么??这就是和mysql的另一机制有关了。
接下来我们简单介绍下Undo Log

Undo Log

事务开始之前,操作任何数据之前,将需要操作的数据备份到一个地方(Undo Log),当事务执行过程中出现错误或者ROLLBACK,MySQL利用备份将数据恢复到开始事务之前。
Undo Log保证事务的原子性.
在InnoDB引擎中实现多版本并发控制。
事务未提交前,undolog中数据可以作为数据旧版本提供对其他并发事务实现快照读
除了Undo log之外,MySQL还有另外一种日志redo log

Redo Log

在事务执行过程中,将最新的数据备份到一个地方(Redo Log),
在发生故障的时候,还有脏页未刷到磁盘,在重启mysql的时候,根据Redo log 重做,从而达到事务的未落磁盘数据进行持久化的这一特性。
Redo Log实现事务的持久性
在这里插入图片描述
留给读者一个思考题:请问Redo Log和binglog有什么区别你能说出来吗?

以上乃个人学习总结,若有不对之处,欢迎指出,谢谢阅读!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值