继续更新《Java面试必知必会》系列了,关于Java基础方面的面试高频已经更新完毕,近期更新的主要是MySQL数据库方面的高频考点,很多岗位都会在面试的时候问一些数据库相关的知识,建议大家收藏一波,绝对干货!
推荐阅读
第一章:Java基础知识在面试中的高频考点
第二章:Java集合在面试中的高频考点
第三章:Java多线程与并发编程在面试中的高频考点
第四章:Java虚拟机在面试中的高频考点
第五章:MySQL数据库中的索引常见高频考点
目录标题- 1.什么是锁,锁的作用是什么?
- 2.数据库有哪些锁?lock和latch的区别
- 3.InnoDB存储引擎中的锁都有哪些类型?
- 4.什么是一致性非锁定读(MVCC)?
- 什么是MVCC?
- MVCC能解决什么问题,好处是?
- MVCC带来的好处是?
- 核心概念【很重要!!!】
- 5.锁可能会带来什么问题?
- 6.数据库中的死锁概念你知道吗?
回答:锁是数据库系统区别文件系统的一个关键特性,锁机制用于管理对共享资源的并发访问,保持数据的完整性和一致性。【摘自:MySQL技术内幕InnoDB存储引擎】
2.数据库有哪些锁?lock和latch的区别回答:数据库中有表锁和行锁等
lock锁:锁的对象是事务,用于锁定数据库中的对象,如表、页、行等,并且lock锁一般在commit或rollback后释放,有死锁机制。
latch锁:一般称为轻量级锁,要求锁定的时间必须非常短,在InnoDB中又可以分为mutex(互斥量)和rwlock(读写锁)。目的是用来保证并发线程 *** 作临界资源的正确性,并且通常没有死锁检测的机制。
3.InnoDB存储引擎中的锁都有哪些类型?回答:可以分为共享锁、排他锁、意向锁、一致性非锁定读和一致性锁定读。
其中共享锁和排他锁均属于行级锁。
共享锁(S Lock):运行事务读一行数据。
排他锁(X Lock):允许事务删除或更新一行数据。
行锁的三种算法:
Record Lock:单个行记录上的锁
Gap Lock:间隙锁,锁定一个范围,但不包含记录本身。
Next-Key Lock:Gap+Record Lock锁定一个范围,并且锁定记录本身。
意向锁属于表级别的锁,又可以分为意向共享锁(IS Lock)和意向排他锁(IX Lock)。
意向共享锁(IS Lock):事务想要获得一张表中某几行的共享锁。
意向排他锁(IX Lock):事务想要获得一张表中某几行的排他锁。
一致性非锁定读:指InnoDB存储引擎通过多版本控制的方式来读取当前执行时间数据库中行的数据。如果读取的行正在执行DELETE或UPDATE *** 作,这时读取 *** 作不会因此等待行上锁的释放,相反的,InnoDB存储引擎会读取一个快照数据。
一致性锁定读:InnoDB存储引擎对于SELECT语句支持两种一致性锁定读的 *** 作:
select … for update和select … lock in share mode。
4.什么是一致性非锁定读(MVCC)? 什么是MVCC?MVCC实现原理【MVCC多版本并发控制,指的是一种提高并发的技术。】
Multi-Version Concurrency Control。
最早的数据库系统,只有读读之间可以并发,读写,写读,写写都要阻塞。引入多版本之后,只有写写之间相互阻塞,其他三种 *** 作都可以并行,这样大幅度提高了InnoDB的并发度。
数据库并发场景有三种,分别为:
读-读:不存在任何问题,也不需要并发控制
读-写:有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读,不可重复读
写-写:有线程安全问题,可能会存在更新丢失问题,比如第一类更新丢失,第二类更新丢失
MVCC可以为数据库解决以下问题
在并发读写数据库时,可以做到在读 *** 作时不用阻塞写 *** 作,写 *** 作也不用阻塞读 *** 作,提高了数据库并发读写的性能
同时还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决更新丢失问题
MVCC只在读取已提交和可重复 读两种隔离级别下有作用
MVCC常见的实现方式乐观锁和悲观锁
MVCC是行级锁的变种,很多情况下避免了加锁 *** 作。
应对高并发事务, MVCC比单纯的加锁更高效;
InnoDB存储引擎在数据库每行数据的后面添加了三个字段, 不是两个!!
核心概念【很重要!!!】1.Read view一致性视图【 主要是用来做可见性判断的, 比较普遍的解释便是"本事务不可见的当前其他活跃事务", 】
2.read view快照的生成时机, 也非常关键, 正是因为生成时机的不同, 造成了RC,RR两种隔离级别的不同可见性;
在innodb中(默认repeatable read级别), 事务在begin/start
transaction之后的第一条select读 *** 作后, 会创建一个快照(read view), 将当前系统中活跃的其他事务记录记录起来;
在innodb中(默认repeatable committed级别), 事务中每条select语句都会创建一个快照(read view);
3.undo-log 【回滚日志,通过undo读取之前的版本信息,以此实现非锁定读取!】 是MVCC的重要组成部分!
当我们对记录做了变更 *** 作时就会产生undo记录,Undo记录默认被记录到系统表空间(ibdata)中,但从5.6开始,也可以使用独立的Undo 表空间。
Undo记录中存储的是老版本数据,当一个旧的事务需要读取数据时,为了能读取到老版本的数据,需要顺着undo链找到满足其可见性的记录。
另外, 在回滚段中的undo logs分为: insert undo log 和 update undo log insert undo
insert undo log : 事务对insert新记录时产生的undolog, 只在事务回滚时需要, 并且在事务提交后就可以立即丢弃。 update undo
update undo log : 事务对记录进行delete和update *** 作时产生的undo log, 不仅在事务回滚时需要,
一致性读也需要,所以不能随便删除,只有当数据库所使用的快照中不涉及该日志记录,对应的回滚日志才会被purge线程删除。
4.InnoDB存储引擎在数据库每行数据的后面添加了三个字段
分别是事务ID、回滚指针和
6字节的DB_ROW_ID字段: 包含一个随着新行插入而单调递增的行ID, 当由innodb自动产生聚集索引时,聚集索引会包括这个行ID的值,否则这个行ID不会出现在任何索引中。
5.可见性比较算法(这里每个比较算法后面的描述是建立在rr级别下,rc级别也是使用该比较算法,此处未做描述)
设要读取的行的最后提交事务id(即当前数据行的稳定事务id)为 trx_id_current
当前新开事务id为 new_id
当前新开事务创建的快照read view 中最早的事务id为up_limit_id, 最迟的事务id为low_limit_id(注意这个low_limit_id=未开启的事务id=当前最大事务id+1)
比较:
- trx_id_current < up_limit_id, 这种情况比较好理解, 表示, 新事务在读取该行记录时, 该行记录的稳定事务ID是小于, 系统当前所有活跃的事务, 所以当前行稳定数据对新事务可见, 跳到步骤5.
- trx_id_current >= trx_id_last, 这种情况也比较好理解, 表示, 该行记录的稳定事务id是在本次新事务创建之后才开启的,但是却在本次新事务执行第二个select前就commit了,所以该行记录的当前值不可见, 跳到步骤4
- trx_id_current <= trx_id_current <= trx_id_last, 表示: 该行记录所在事务在本次新事务创建的时候处于活动状态,从up_limit_id到low_limit_id进行遍历,如果trx_id_current等于他们之中的某个事务id的话,那么不可见,调到步骤4,否则表示可见。
- 从该行记录的 DB_ROLL_PTR 指针所指向的回滚段中取出最新的undo-log的版本号, 将它赋值该 trx_id_current,然后跳到步骤1重新开始判断。
- 将该可见行的值返回。
回答:通过锁机制实现了事务的隔离性,使得事务可以并发的工作,但同时也会有一些潜在的问题。锁会带来如下问题:脏读、不可重复度、丢失修改和幻读。
- 脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的 *** 作可能是不正确的。
- 丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。
- 不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
- 幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
不可重复读和幻读区别:
不可重复读的重点是修改比如多次读取一条记录发现其中某些列的值被修改,幻读的重点在于新增或者删除比如多次读取一条记录发现记录增多或减少了。【摘自MySQL技术内幕:InnoDB存储引擎可以使用Next-Key Locking机制来避免Phantom Problem问题】
6.数据库中的死锁概念你知道吗?回答:死锁是指两个或两个以上的事务在执行过程中,因争夺资源而造成的一种互相等待的现象。
解决死锁的办法:一种是超时回滚,一种是采用死锁检测机制(wait-for graph等待图)
如果面试官让你举例子,可以举例下面的例子:
在 MySQL 中,gap lock 默认是开启的,即innodb_locks_unsafe_for_binlog 参数值是disable 的,且 MySQL 中默认的是 RR 事务隔离级别。
当我们执行以下查询 SQL 时,由于 order_no 列为非唯一索引,此时又是 RR 事务隔离级别,所以 SELECT 的加锁类型为 gap lock,这里的 gap 范围是 (4,+∞)。
执行查询 SQL 语句获取的 gap lock 并不会导致阻塞,而当我们执行以下插入 SQL 时,会在插入间隙上再次获取插入意向锁。插入意向锁其实也是一种 gap 锁,它与 gap lock 是冲突的,所以当其它事务持有该间隙的 gap lock 时,需要等待其它事务释放 gap lock 之后,才能获取到插入意向锁。
以上事务 A 和事务 B 都持有间隙 (4,+∞)的 gap 锁,而接下来的插入 *** 作为了获取到插入意向锁,都在等待对方事务的 gap 锁释放,于是就造成了循环等待,导致死锁。
最后送上锁之间的兼容性表格:
推荐阅读
第一章:Java基础知识在面试中的高频考点
第二章:Java集合在面试中的高频考点
第三章:Java多线程与并发编程在面试中的高频考点
第四章:Java虚拟机在面试中的高频考点
第五章:MySQL数据库中的索引常见高频考点
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)