内容简介:对于大部分的后端开发来说,数据库尤其是MySQL是一个离不开的知识点,那么今天就分享一下最近学习的数据库中的锁相关知识,并以此解释事务隔离性问题。如下是整理的Mysql中锁的相关知识点锁是数据库系统区别于文件系统的一个关键性区别。锁机制用于管理数据库共享资源的并发访问。也是实现事务的关键。
对于大部分的后端开发来说,数据库尤其是 MySQL 是一个离不开的知识点,那么今天就分享一下最近学习的数据库中的锁相关知识,并以此解释事务隔离性问题。
如下是整理的Mysql中锁的相关知识点
什么是锁
锁是数据库系统区别于文件系统的一个关键性区别。锁机制用于管理数据库共享资源的并发访问。也是实现事务的关键。
锁的级别
在MySQL中根据锁的粒度分为全局锁,表锁和行锁,锁的粒度从大到小。
-
全局锁:锁住的是数据库实例,被锁住时只读不可写。需要显示的调用锁库语句:Flush table with lock。 使用场景一般是全库备份。
-
表锁:分为表锁和元数据锁(MDL)
表锁类似全局锁,只是锁住对象时表,分读锁和写锁。
元数据锁(MDL),不需要显示的调用,当对一个表进行增删改查时会加MDL读锁 ,当对表结构进行修改时(如加减字段)那么此时会对表加上写锁。这里的 读锁之间是不会互相排斥的,但是写锁是互斥的
-
行锁:对表中的具体记录进行加锁,是项目中最常见的一种锁。 行锁是对索引加锁 。之前说过,每一张表都是有索引的,如果有主键,主键会键索引,如果没有主键,Innodb会为每行记录加一个默认列row_index 在这个列上面会建立索引。
锁的分类
InnoDB实现了如下两种标准的行级锁:
- 共享锁 (S Lock),允许事务读取一行数据。
- 排他锁(X Lock),允许事务删除或者更新一行数据。
如下图显示了共享锁和排他锁的兼容性
只有同时是S 共享锁时才能在不同的事务中进行读取。
锁的算法
在对锁有了简单的了解后,下面就来说说锁的算法。
- Record Lock : 行记录锁,属于X 排他锁。
- Gap Lock :间隙锁,也叫范围锁,对索引之间的范围加锁。
- Next Key Lock :行记录锁+间隙锁的组合。
大家可能对前面两个比较好理解,对于第三个Next Key Lock会略感陌生,那么下面就是对该算法的解释。
假设表上面id列有索引4,5,7,10)这四个值,那么加锁的情况就是(-无穷大,4],(4,5],(5,7],(7,10],(10,+无穷大),如果id不是聚簇索引或者唯一索引,那么执行select * from t where id=5 for update ,加锁的情况就是 (4,5)和(5,7)那么 insert into t select 6 ;会被锁住无法插入,但是insert into t select 8,或者insert into t select 2都是可以插入。
在可重复读的隔离级别下默认使用的是Next Key Lock,通过这个锁算法可以解决幻读问题。使用读提交的隔离级别会关闭Gap Lock和Next Key Lock 。
锁带来的问题
正是因为有了锁我们可以对共享资源进行并发控制,但带来便利的同时,也带来了其他问题。
两阶段协议
在继续往下讲之前,我们需要了解什么是 锁的两阶段协议
1 . 锁在需要的时候才会加上去;
2. 事务结束才会释放锁。
怎么理解呢?
通俗的讲就是,事务开启时不会立马加锁,只有在执行需要加锁的 sql 时才会加上锁比如insert ,delete等;但是锁的释放是等事务提交时才会释放,而不是执行完sql就释放锁。也正是由于这个原因才出现了阻塞和死锁的现象。
阻塞
由于不同锁之间的兼容问题,在有些时刻,一个事务中的锁需要等待另一个事务中的锁的释放它锁占用的资源,这个就是 阻塞 。
在Innodb中,有一个参数innodb_lock_wait_timeout 是用来控制等待时间的,默认是50秒,当一个事务等待超时时会出现1205异常, 在默认情况下Innodb不会回滚超时引发的错误异常(在Innodb中大部分异常不会有回滚操作除了死锁检测) 。如果想回滚可以业务自己手动调用,或者将参数innodb_rollback_on_timeout设置为on,默认是off。
死锁
和 java 中死锁的概念差不多,具体是指:两个或者两个以上的事务在执行过程中,因为争夺锁资源而造成的一种互相等待的现象。
死锁原因
在上面有提到两阶段的协议,也正是其中提到的事务提交时才会释放锁,那么就会在事务结束时出现AB和BA的互相等待锁的情况。这个就是导致死锁的原因。
如何解决
对于死锁问题的解决一般有三种方向
- 数据库默认的一个参数是innodb_lock_wait_timeout ,这个是事务等待超时,也是用来做锁等待超时的
- 打开死锁检测,innodb_deadlock_detect=ON
- 在业务端控制并发,比如对热点的数据做缓存或者使用队列进行数据库操作
解释一下什么 死锁检测 :
为了能够主动进行死锁检测,数据库中保存了2种信息 “锁的链表信息”和“事务等待链表”,通过这两个链表可以构造出一张以事务为节点的图(wait-for graph),图中事务节点可以互相指向,当T1等待T2锁占用的资源时,会有一个T1指向T2的定义,当事务请求锁时就会检测这张图,如果出现循环指向,那么就会报1213异常,这时会将undo log量最少的事务进行回滚。
死锁的检测会导致机器的cpu利用率高,尤其是在并发度较高时,因此可以通过innodb_deadlock_detect开关来关闭死锁检测。 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 你了解HTTPS,但你可能不了解X.509
- 你真的了解Mybatis的${}和#{}吗?是否了解应用场景?
- 你所了解的 array_diff_uassoc 真的是你了解的那样吗?
- 图文了解 Kubernetes
- 深入了解 JSONP
- 一文了解 Kubernetes
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。