Mysql事务隔离级别与锁机制学习总结

事务及其ACID属性

原子性(Atomicity) : 事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
一致性(Consistent) : 在事务开始和完成时,数据都必须保持一致状态。
隔离性(Isolation) : 事务处理过程中的状态对其他事务是不可见的。
持久性(Durable) : 事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

并发事务处理带来的问题

脏写: 当两个或多个事务选择同一行,就有可能最后的更新覆盖了其他事务的更新结果。
脏读: 事务A读取到了事务B已经修改但尚未提交的数据,如果B事务回滚,A读取的数据就是无效的。
幻读: 事务A读取到了事务B提交的新增数据,不符合隔离性
可重复读 : 事务A内部的相同查询语句在不同时刻读出的结果一致
不可重复读 : 事务A中相同查询语句在下一时刻读到了事务B修改后的数据,导致结果不一致
“脏读”、“不可重复读”和“幻读”,都是数据库读一致性问题,可以通过一定的事务隔离机制来解决。

幻读和不可重复读区别:

不可重复读的重点是修改,同样的条件, 你读取过的数据, 再次读取出来发现值不一样了
幻读的重点在于新增或者删除,同样的条件, 第1次和第2次读出来的记录数不一样
从总的结果来看, 两者都表现为两次读取的结果不一致,但从控制的角度来看, 两者的区别就比较大,不可重复读只需要锁住满足条件的记录。对于后者,要锁住满足条件及其相近的记录。

事务隔离级别

在这里插入图片描述
读未提交: 存在脏读、不可重复读、幻读问题。
读已提交: 解决了脏读问题,仍然存在不可重复读、幻读问题。
可重复读: Mysql默认隔离级别,只存在幻读,由于可重复机制,查询是查不到其他事物新增的数据的,但可以对查询不到的数据进行修改。如果要保证事务隔离性,需要对行加锁,MVCC机制通过无锁解决了事务隔离性问题。
可串行化: 事务A执行范围查询时,会把范围内的所有行、包括每行记录所在的间隙区间都加锁(间隙锁)此时如果客户端B在该范围内插入数据都会被阻塞,所以就避免了幻读,因为加锁粒度大,所以性能低。

Mysql锁

锁分类
1、从性能上分为乐观锁和悲观锁
乐观锁和悲观锁不是真正的锁,只是锁的两种实现方式
乐观锁:
操作数据时不会直接对操作的数据进行加锁,可以多个事务并行对同一数据进行操作,数据提交的时候验证数据是否存在冲突,可以用版本号对比机制来实现。
版本号对比机制:有A、B两个事务对同一行数据进行操作,A、B都会先查出当前数据以及版本号,A先修改了数据,提交时验证查询时的版本与当前数据版本是否匹配,匹配成功之后提交,提交同时还会修改数据的版本号,修改的过程需要加锁。此时B也修改完成去提交数据,但A修改了数据的版本号,B的版本号就不匹配了,所以提交失败或者重新查询后再重试。

乐观锁适用于读多写少的场景,可以省去频繁加锁、释放锁的开销,提高吞吐量
悲观锁:
操作数据时直接对数据加锁,数据库中的行锁,表锁,读锁,写锁,以及 syncronized 实现的锁均为悲观锁。
悲观锁适用于写比较多的场景,在扣减商品库存时就可以根据悲观锁思路来实现锁机制,乐观锁会因为版本不一致,不断重试更新,产生大量自旋,消耗CPU,影响性能。
2、从对数据库操作的类型分为读锁和写锁,还有意向锁

读锁(共享锁,S锁(Shared)):
针对同一条数据,多个读操作可以同时进行而不会互相影响。
写锁(排它锁,X锁(eXclusive)):
当前写操作没完成前,会阻断其他写锁和读锁,update操作都会加写锁,查询也可以在最后加 for update加写锁
意向锁(Intention Lock):
又称I锁,针对表锁,有事务给表的数据行加了读锁或写锁时会给表设置一个标识,代表已经有行锁了。其他事务要想对表加表锁时,就不用逐行判断有没有行锁跟表锁冲突了,直接读这个标识就可以确定该不该加表锁,这个标识就是意向锁。

3、从对数据操作的粒度分为表锁和行锁

表锁:
每次操作锁住整张表,开销小,加锁快,不会出现死锁,但是锁定粒度大,发生锁冲突的概率最高,并发度低。
行锁:
每次操作锁住一行数据,开销大,加锁慢,会出现死锁,但锁定粒度最小,发生锁冲突的概率最低,并发度最高。行锁在 InnoDB 中是基于索引实现的,所以一旦某个加锁操作没有使用索引,那么该锁就会退化为表锁。
无索引的字段行锁会升级为表锁
MyISAM在执行查询语句前,会给涉及的表加读锁,在update、insert、delete时会给涉及的表加写锁。
InnoDB在执行查询语句时不会加锁(非串行隔离级别)。但update、insert、delete时会加行锁。
InnoDB支持事务、支持行锁 Mylsam不支持

4、间隙锁(gap lock):
间隙锁存在于非唯一索引中,锁定开区间范围内的一段间隔,它是基于临键锁实现的,在请求共享或排他锁时,用的条件不是相等而是范围,InnoDB会给符合条件范围之间的所有数据索引,以及范围之间可能插入的数据索引加间隙锁,它会把锁定范围扩大。
例如表中有1、2、3、10、20四个id,那么间隙就有 (3,10),(10,20),(20,正无穷) 这三个开区间,这个范围所包含的所有行记录以及间隙中可能插入的记录都会被加锁。
例:执行update test set name = ‘zhangsan’ where id > 8 and id <18;时,因为8在第一个区间,18在第二个区间,所前二个区间都会被锁住,此时操作id(3,20)区间,也3-20之间,不包括3和20的数据就会失败。
间隙锁是在可重复读隔离级别下才会生效
Mysql中innodb_locks_unsafe_for_binlog这个参数默认值是OFF, 也就是启用间隙锁, 他是一个bool值, 当值为true时表示关闭间隙锁。
5、临键锁(Next-Key lock):
临键锁存在于非唯一索引中,该类型的每条记录的索引上都存在这种锁,它是一种特殊的间隙锁,锁定一段左开右闭的索引区间。在唯一索引列上不存在临键锁。InnoDB 通过 MVCC 和 临键锁,解决了在可重复读的事务隔离级别下,当前读(update、insert、delete时的读)出现幻读的问题。像上面那个例子里的(负无穷大,1],(3,10],(10,20],(20,正无穷]几个区间都是临键锁。

锁分析sql总结

行锁分析:

show status like 'innodb_row_lock%';

状态说明:
Innodb_row_lock_waits: 系统启动到现在等待的总次数
Innodb_row_lock_time: 从系统启动到现在锁定总时间长度
Innodb_row_lock_time_avg: 平均等待时长
Innodb_row_lock_time_max:从系统启动到现在等待最长的一次所花时间
Innodb_row_lock_current_waits: 当前正在等待锁定的数量

查看系统库中锁相关数据表:
查看事务

select * from INFORMATION_SCHEMA.INNODB_TRX;

查看锁

select * from INFORMATION_SCHEMA.INNODB_LOCKS;

查看等待锁

select * from INFORMATION_SCHEMA.INNODB_LOCK_WAITS;

释放锁:从INNODB_TRX事物表里查到trx_mysql_thread_id,再使用kill命令杀掉

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值