0、概要
1、谈⼀谈MySQL的读写锁
2、隔离级别与锁的关系
3、按照锁的粒度分数据库锁有哪些?锁机制与InnoDB锁算法
4、从锁的类别上分MySQL都有哪些锁呢?像上⾯那样⼦进⾏锁定岂不是有点阻碍并发效率了
5、MySQL中InnoDB引擎的⾏锁是怎么实现的?
6、InnoDB存储引擎的锁的算法有三种
7、什么是死锁?怎么解决?
8、数据库的乐观锁和悲观锁是什么?怎么实现的?
1、谈⼀谈MySQL的读写锁
出现概率: ★★★★★
在处理并发读或写时,可以通过实现⼀个由两种类型组成的锁系统来解决问题。这两种类型的锁通常被称为共享锁和排它锁,也叫读锁和写锁。读锁是共享的,相互不阻塞,多个客户在同⼀时刻可以同时读取同⼀个资源⽽不相互⼲扰。写锁则是排他的,也就是说⼀个写锁会阻塞其他的写锁和读锁,确保在给定时间内只有⼀个⽤户能执⾏写⼊并防⽌其他⽤户读取正在写⼊的同⼀资源。
在实际的数据库系统中,每时每刻都在发⽣锁定,当某个⽤户在修改某⼀部分数据时,MySQL 会通过锁定防⽌其他⽤户读取同⼀数据。写锁⽐读锁有更⾼的优先级,⼀个写锁请求可能会被插⼊到读锁队列的前⾯,但是读锁不能插⼊到写锁前⾯。
2、隔离级别与锁的关系
出现概率: ★★★
在Read Uncommitted级别下,读取数据不需要加共享锁,这样就不会跟被修改的数据上的排他锁冲突
在Read Committed级别下,读操作需要加共享锁,但是在语句执⾏完以后释放共享锁;
在Repeatable Read级别下,读操作需要加共享锁,但是在事务提交之前并不释放共享锁,也就是必须等待事务执⾏完毕以后才释放共享锁。SERIALIZABLE 是限制性最强的隔离级别,因为该级别锁定整个范围的键,并⼀直持有锁,直到事务完成。
3、按照锁的粒度分数据库锁有哪些?锁机制与InnoDB锁算法
出现概率: ★★★
在关系型数据库中,可以按照锁的粒度把数据库锁分为⾏级锁(INNODB引擎)、表级锁(MYISAM引擎)和⻚级锁(BDB引擎 )。
MyISAM和InnoDB存储引擎使⽤的锁:
MyISAM采⽤表级锁(table-level locking)。
InnoDB⽀持⾏级锁(row-level locking)和表级锁,默认为⾏级锁
⾏级锁,表级锁和⻚级锁对⽐
⾏级锁 ⾏级锁是Mysql中锁定粒度最细的⼀种锁,表示只针对当前操作的⾏进⾏加锁。⾏级锁能⼤⼤减少数据库操作的冲突。其加锁粒度最⼩,但加锁的开销也最⼤。⾏级锁分为共享锁 和 排他锁。
特点:开销⼤,加锁慢;会出现死锁;锁定粒度最⼩,发⽣锁冲突的概率最低,并发度也最⾼。
表级锁 表级锁是MySQL中锁定粒度最⼤的⼀种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被⼤部分MySQL引擎⽀持。最常使⽤的MYISAM与INNODB都⽀持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。
特点:开销⼩,加锁快;不会出现死锁;锁定粒度⼤,发出锁冲突的概率最⾼,并发度最低。
⻚级锁 ⻚级锁是MySQL中锁定粒度介于⾏级锁和表级锁中间的⼀种锁。表级锁速度快,但冲突多,⾏级冲突少,但速度慢。所以取了折衷的⻚级,⼀次锁定相邻的⼀组记录。
特点:开销和加锁时间界于表锁和⾏锁之间;会出现死锁;锁定粒度界于表锁和⾏锁之间,并发度⼀般
4、从锁的类别上分MySQL都有哪些锁呢?像上⾯那样⼦进⾏锁定岂不是有点阻碍并发效率了
出现概率: ★★★
从锁的类别上来讲,有共享锁和排他锁。
共享锁: ⼜叫做读锁。当⽤户要进⾏数据的读取时,对数据加上共享锁。共享锁可以同时加上多个。
排他锁: ⼜叫做写锁。当⽤户要进⾏数据的写⼊时,对数据加上排他锁。排他锁只可以加⼀个,他和其他的排他锁,共享锁都相斥。
⽤上⾯的例⼦来说就是⽤户的⾏为有两种,⼀种是来看房,多个⽤户⼀起看房是可以接受的。⼀种是真正的⼊住⼀晚,在这期间,⽆论是想⼊住的还是想看房的都不可以。
锁的粒度取决于具体的存储引擎,InnoDB实现了⾏级锁,⻚级锁,表级锁。
他们的加锁开销从⼤到⼩,并发能⼒也是从⼤到⼩。
5、MySQL中InnoDB引擎的⾏锁是怎么实现的?
出现概率: ★★★★
答:InnoDB是基于索引来完成⾏锁
select * from tab_with_index where id = 1 for update;
for update 可以根据条件来完成⾏锁锁定,并且 id 是有索引键的列,如果 id 不是索引键那么InnoDB将完成表锁,并发将⽆从谈起
6、InnoDB存储引擎的锁的算法有三种
Record lock:单个⾏记录上的锁
Gap lock:间隙锁,锁定⼀个范围,不包括记录本身
Next-key lock:record+gap 锁定⼀个范围,包含记录本身
7、什么是死锁?
出现概率: ★★★★★
死锁是指两个或多个事务在同⼀资源上相互占⽤,并请求锁定对⽅的资源,从⽽导致恶性循环的现象。
8、常⻅的解决死锁的⽅法
出现概率: ★★★★★
死锁是指多个事务在同⼀资源上相互占⽤并请求锁定对⽅占⽤的资源⽽导致恶性循环的现象。当多个事务试图以不同顺序锁定资源时就可能会产⽣死锁,多个事务同时锁定同⼀个资源时也会产⽣死锁。
为了解决死锁问题,数据库系统实现了各种死锁检测和死锁超时机制。越复杂的系统,例如InnoDB 存储引擎,越能检测到死锁的循环依赖,并⽴即返回⼀个错误。这种解决⽅式很有效,否则死锁会导致出现⾮常慢的查询。还有⼀种解决⽅法,就是当查询的时间达到锁等待超时的设定后放弃锁请求,这种⽅式通常来说不太好。InnoDB ⽬前处理死锁的⽅法是将持有最少⾏级排它锁的事务进⾏回滚。
死锁发⽣之后,只有部分或者完全回滚其中⼀个事务,才能打破死锁。对于事务型系统这是⽆法避免的,所以应⽤程序在设计时必须考虑如何处理死锁。⼤多数情况下只需要重新执⾏因死锁回滚的事务即可。
9、数据库的乐观锁和悲观锁是什么?怎么实现的?
出现概率: ★★★★★
数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同⼀数据时不破坏事务的隔离性和统⼀性以及数据库的统⼀性。乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采⽤的技术⼿段。
悲观锁:假定会发⽣并发冲突,屏蔽⼀切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。实现⽅式:使⽤数据库中的锁机制
乐观锁:假设不会发⽣并发冲突,只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来,通过version的⽅式来进⾏锁定。实现⽅式:乐⼀般会使⽤版本号机制或CAS算法实现。
两种锁的使⽤场景
从上⾯对两种锁的介绍,我们知道两种锁各有优缺点,不可认为⼀种好于另⼀种,像乐观锁适⽤于写⽐较少的情况下(多读场景),即冲突真的很少发⽣的时候,这样可以省去了锁的开销,加⼤了系统的整个吞吐量。
但如果是多写的情况,⼀般会经常产⽣冲突,这就会导致上层应⽤会不断的进⾏retry,这样反倒是降低了性能,所以⼀般多写的场景下⽤悲观锁就⽐较合适。