对于大部分的后端开发来讲,数据库尤为是MySQL是一个离不开的知识点,那么今天就分享一下最近学习的数据库中的锁相关知识,并以此解释事务隔离性问题。
以下是整理的Mysql中锁的相关知识点 java
锁是数据库系统区别于文件系统的一个关键性区别。锁机制用于管理数据库共享资源的并发访问。也是实现事务的关键。算法
在MySQL中根据锁的粒度分为全局锁,表锁和行锁,锁的粒度从大到小。sql
全局锁:锁住的是数据库实例,被锁住时只读不可写。须要显示的调用锁库语句:Flush table with lock。 使用场景通常是全库备份。数据库
表锁 :分为表锁和元数据锁(MDL)后端
表锁相似全局锁,只是锁住对象时表,分读锁和写锁。
元数据锁(MDL),不须要显示的调用,当对一个表进行增删改查时会加MDL读锁 ,当对表结构进行修改时(如加减字段)那么此时会对表加上写锁。这里的读锁之间是不会互相排斥的,可是写锁是互斥的缓存
行锁:对表中的具体记录进行加锁,是项目中最多见的一种锁。行锁是对索引加锁。以前说过,每一张表都是有索引的,若是有主键,主键会键索引,若是没有主键,Innodb会为每行记录加一个默认列row_index 在这个列上面会创建索引。并发
InnoDB实现了以下两种标准的行级锁:学习
以下图显示了共享锁和排他锁的兼容性 spa
在对锁有了简单的了解后,下面就来讲说锁的算法。
3d
你们可能对前面两个比较好理解,对于第三个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的互相等待锁的状况。这个就是致使死锁的缘由。
对于死锁问题的解决通常有三种方向
解释一下什么死锁检测:
为了可以主动进行死锁检测,数据库中保存了2种信息 “锁的链表信息”和“事务等待链表”,经过这两个链表能够构造出一张以事务为节点的图(wait-for graph),图中事务节点能够互相指向,当T1等待T2锁占用的资源时,会有一个T1指向T2的定义,当事务请求锁时就会检测这张图,若是出现循环指向,那么就会报1213异常,这时会将undo log量最少的事务进行回滚。
死锁的检测会致使机器的cpu利用率高,尤为是在并发度较高时,所以能够经过innodb_deadlock_detect开关来关闭死锁检测。
复制代码
今天主要分析了MySQL中的锁的相关知识,只有认识了锁那么在解决数据库方面的问题时才会更加驾轻就熟。你们若是有问题能够一块儿讨论。
未完待续!!!!