C++岗位求职面试八股文第二十一篇(数据库)

系列文章目录

第一篇:语言基础
第二篇:设计模式
第三篇:数据库
第四篇:计算机网络
第五篇:操作系统
第六篇:LInux
第七篇:数据结构
第八篇:智力题

[81]说一说你对数据库事务的了解

事务可由一条或由一组SQL语句组成。在事务中的操作,要么都执行修改,要么都不执行,这就是事务的目的,也是事务模型区别于文件系统的重要特征之一。

事务需遵循ACID四个特性:
A(atomicity),原子性。原子性指整个数据库事务是不可分割的工作单位。只有使事务中所有的数据库操作都执行成功,整个事务的执行才算成功。事务中任何一个SQL语句执行失败,那么已经执行成功的SQL语句也必须撤销,数据库状态应该退回到执行事务前的状态。
C(consistency),一致性。一致性指事务将数据库从一种状态转变为另一种一致的状态。在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
I(isolation),隔离性。允许多个并发事务同时对数据进⾏修改和读写的能⼒,它可以防⽌由于多个事务并发执⾏时由 于交叉执⾏⽽导致的数据不⼀致
D(durability) ,持久性。事务一旦提交,其结果就是永久性的,即使发生宕机等故障,数据库也能将数据恢复。持久性保证的是事务系统的高可靠性,而不是高可用性。

事务可以分为以下几种类型:
1扁平事务:是事务类型中最简单的一种,而在实际生产环境中,这可能是使用最为频繁的事务。在扁平事务中,所有操作都处于同一层次,其由BEGIN WORK开始,由COMMIT WORK或ROLLBACK WORK结束。处于之间的操作是原子的,要么都执行,要么都回滚。
2带有保存点的扁平事务:除了支持扁平事务支持的操作外,允许在事务执行过程中回滚到同一事务中较早的一个状态,这是因为可能某些事务在执行过程中出现的错误并不会对所有的操作都无效,放弃整个事务不合乎要求,开销也太大。保存点(savepoint)用来通知系统应该记住事务当前的状态,以便以后发生错误时,事务能回到该状态。
3链事务:可视为保存点模式的一个变种。链事务的思想是:在提交一个事务时,释放不需要的数据对象,将必要的处理上下文隐式地传给下一个要开始的事务。注意,提交事务操作和开始下一个事务操作将合并为一个原子操作。这意味着下一个事务将看到上一个事务的结果,就好像在一个事务中进行的。
4嵌套事务:是一个层次结构框架。有一个顶层事务(top-level transaction)控制着各个层次的事务。顶层事务之下嵌套的事务被称为子事务(subtransaction),其控制每一个局部的变换。
5分布式事务:通常是一个在分布式环境下运行的扁平事务,因此需要根据数据所在位置访问网络中的不同节点。对于分布式事务,同样需要满足ACID特性,要么都发生,要么都失效。
对于MySQL的InnoDB存储引擎来说,它支持扁平事务、带有保存点的扁平事务、链事务、分布式事务。对于嵌套事务,MySQL数据库并不是原生的,因此对于有并行事务需求的用户来说MySQL就无能为力了,但是用户可以通过带有保存点的事务来模拟串行的嵌套事务。

[82]MySQL的ACID特性分别是怎么实现的?

原子性实现原理:
实现原子性的关键,是当事务回滚时能够撤销所有已经成功执行的sql语句。InnoDB实现回滚靠的是undo log,当事务对数据库进行修改时,InnoDB会生成对应的undo log。如果事务执行失败或调用了rollback,导致事务需要回滚,便可以利用undo log中的信息将数据回滚到修改之前的样子。
undo log属于逻辑日志,它记录的是sql执行相关的信息。当发生回滚时,InnoDB会根据undo log的内容做与之前相反的工作。对于insert,回滚时会执行delete。对于delete,回滚时会执行insert。对于update,回滚时则会执行相反的update,把数据改回去。

持久性实现原理:
InnoDB作为MySQL的存储引擎,数据是存放在磁盘中的,但如果每次读写数据都需要磁盘IO,效率会很低。为此,InnoDB提供了缓存(Buffer Pool),Buffer Pool中包含了磁盘中部分数据页的映射,作为访问数据库的缓冲。当从数据库读取数据时,会首先从Buffer Pool中读取,如果Buffer Pool中没有,则从磁盘读取后放入Buffer Pool。当向数据库写入数据时,会首先写入Buffer Pool,Buffer Pool中修改的数据会定期刷新到磁盘中(这一过程称为刷脏)。
Buffer Pool的使用大大提高了读写数据的效率,但是也带了新的问题:如果MySQL宕机,而此时Buffer Pool中修改的数据还没有刷新到磁盘,就会导致数据的丢失,事务的持久性无法保证。
于是,redo log被引入来解决这个问题。当数据修改时,除了修改Buffer Pool中的数据,还会在redo log记录这次操作。当事务提交时,会调用fsync接口对redo log进行刷盘。如果MySQL宕机,重启时可以读取redo log中的数据,对数据库进行恢复。redo log采用的是WAL(Write-ahead logging,预写式日志),所有修改先写入日志,再更新到Buffer Pool,保证了数据不会因MySQL宕机而丢失,从而满足了持久性要求。
既然redo log也需要在事务提交时将日志写入磁盘,为什么它比直接将Buffer Pool中修改的数据写入磁盘(即刷脏)要快呢?主要有以下两方面的原因:
• 刷脏是随机IO,因为每次修改的数据位置随机,但写redo log是追加操作,属于顺序IO。
• 刷脏是以数据页(Page)为单位的,MySQL默认页大小是16KB,一个Page上一个小修改都要整页写入。而redo log中只包含真正需要写入的部分,无效IO大大减少。

隔离性实现原理:
隔离性追求的是并发情形下事务之间互不干扰。简单起见,我们主要考虑最简单的读操作和写操作(加锁读等特殊读操作会特殊说明),那么隔离性的探讨,主要可以分为两个方面。
第一方面,(一个事务)写操作对(另一个事务)写操作的影响:锁机制保证隔离性。
隔离性要求同一时刻只能有一个事务对数据进行写操作,InnoDB通过锁机制来保证这一点。锁机制的基本原理可以概括为:事务在修改数据之前,需要先获得相应的锁。获得锁之后,事务便可以修改数据。该事务操作期间,这部分数据是锁定的,其他事务如果需要修改数据,需要等待当前事务提交或回滚后释放锁。
按照粒度,锁可以分为表锁、行锁以及其他位于二者之间的锁。表锁在操作数据时会锁定整张表,并发性能较差。行锁则只锁定需要操作的数据,并发性能好。但是由于加锁本身需要消耗资源,因此在锁定数据较多情况下使用表锁可以节省大量资源。MySQL中不同的存储引擎支持的锁是不一样的,例如MyIsam只支持表锁,而InnoDB同时支持表锁和行锁,且出于性能考虑,绝大多数情况下使用的都是行锁。
第二方面,(一个事务)写操作对(另一个事务)读操作的影响:MVCC保证隔离性。
InnoDB默认的隔离级别是RR(REPEATABLE READ),RR解决脏读、不可重复读、幻读等问题,使用的是MVCC。MVCC全称Multi-Version Concurrency Control,即多版本的并发控制协议。它最大的优点是读不加锁,因此读写不冲突,并发性能好。InnoDB实现MVCC,多个版本的数据可以共存,主要基于以下技术及数据结构:

  1. 隐藏列:InnoDB中每行数据都有隐藏列,隐藏列中包含了本行数据的事务id、指向undo log的指针等。
  2. 基于undo log的版本链:每行数据的隐藏列中包含了指向undo log的指针,而每条undo log也会指向更早版本的undo log,从而形成一条版本链。
  3. ReadView:通过隐藏列和版本链,MySQL可以将数据恢复到指定版本。但是具体要恢复到哪个版本,则需要根据ReadView来确定。所谓ReadView,是指事务(记做事务A)在某一时刻给整个事务系统(trx_sys)打快照,之后再进行读操作时,会将读取到的数据中的事务id与trx_sys快照比较,从而判断数据对该ReadView是否可见,即对事务A是否可见。

一致性实现原理:
可以说,一致性是事务追求的最终目标。前面提到的原子性、持久性和隔离性,都是为了保证数据库状态的一致性。此外,除了数据库层面的保障,一致性的实现也需要应用层面进行保障。实现一致性的措施包括:
• 保证原子性、持久性和隔离性,如果这些特性无法保证,事务的一致性也无法保证。
• 数据库本身提供保障,例如不允许向整形列插入字符串值、字符串长度不能超过列的限制等。
• 应用层面进行保障,例如如果转账操作只扣除转账者的余额,而没有增加接收者的余额,无论数据库实现的多么完美,也无法保证状态的一致。

[83]谈谈MySQL的事务隔离级别

SQL 标准定义了四种隔离级别,这四种隔离级别分别是:
• 读未提交(READ UNCOMMITTED);,事务之间完全不隔离,会产⽣脏读,⼀般情况不会使⽤
• 读提交 (READ COMMITTED);本事务读取到的是其它事务提交的最新数据,在同⼀个事务中,前后两相同的 select可能会读到不同的结果
• 可重复读 (REPEATABLE READ);在同⼀个事务中,select的结果是事务开始时时间点的状态,因此,同⼀个事务同样的select 操作可以读到⼀致的结果
• 串行化 (SERIALIZABLE)对同⼀⾏记录,写时加“写锁”,读时加“读锁”,出现冲突时按顺序完成。(我的事务尚未提交,别⼈别想改数据)
事务隔离是为了解决脏读、不可重复读、幻读问题,下表展示了 4 种隔离级别对这三个问题的解决程度:

[84]脏读不可重复读幻读

链接
脏读: ⼀个事务读取另⼀个事务还没有提交的数据
不可重复读: 同⼀个事务内,两个相同的查询返回了不同的结果
幻读:在同⼀个事务中,存在前后两次查询同⼀个范围的数据,查询到的条数不同。幻读仅专指新插⼊的⾏ 存储引擎通过加间隙锁的方式避免幻读
在这里插入图片描述
与标准SQL不同的是,InnoDB存储引擎在REPEATABLE READ事务隔离级别下,使用Next-Key Lock的锁算法,因此避免了幻读的产生。所以,InnoDB存储引擎在默认的事务隔离级别下已经能完全保证事务的隔离性要求,即达到SQL标准的SERIALIZABLE隔离级别。

并发情况下,读操作可能存在的三类问题:

脏读:当前事务(A)中可以读到其他事务(B)未提交的数据(脏数据),这种现象是脏读

不可重复读:在事务A中先后两次读取同一个数据,两次读取的结果不一样,这种现象称为不可重复读。脏读与不可重复读的区别在于:前者读到的是其他事务未提交的数据,后者读到的是其他事务已提交的数据。

幻读:在事务A中按照某个条件先后两次查询数据库,两次查询结果的条数不同,这种现象称为幻读。不可重复读与幻读的区别可以通俗的理解为:前者是数据变了,后者是数据的行数变了。
在这里插入图片描述
行锁只能锁定存在的行,对新插入的行没有限定

[85]间隙锁

在这里插入图片描述
在这里插入图片描述
行锁+间隙锁=next-key lock
可重复度隔离级别下,+间隙锁,实现幻读

[86] MySQL的事务隔离级别是怎么实现的

1Read uncommitted: 性能最好、因为它压根儿就不加锁,没有隔离。
2Read committed:
3Repeated read:
可重复读是在事务开始的时候生成一个当前事务全局性的快照,而读提交则是每次执行语句的时候都重新生成一次快照。对于一个快照来说,它能够读到那些版本数据,要遵循以下规则:
当前事务内的更新,可以读到;
版本未提交,不能读到;
版本已提交,但是却在快照创建后提交的,不能读到;
版本已提交,且是在快照创建前提交的,可以读到。

4Serializable: 读的时候加共享锁,其他事务可以并发读,但是不能写。写的时候加排它锁,其他事务不能并发写也不能并发读。

MySQL 已经在可重复读隔离级别下解决了幻读的问题,用的是间隙锁。MySQL 把行锁和间隙锁合并在一起,解决了并发写和幻读的问题,这个锁叫做 Next-Key锁。

[87]讲⼀下事务,那mysql是如何保证ACID的呢(A:undo-log, I:加行锁,mvcc D:redo-log, 三者共同保证了一致性),那讲⼀下MVCC事务是逻辑上的⼀组操作,要么都执⾏,要么都不执⾏。 事务的四⼤特性原⼦性(undo log保证)、⼀致性(Consistency)、隔离性(锁 和 MVCC 机制保证)、持久性(redo log 保证)。

undo log 名为回滚⽇志,是实现原⼦性的关键,当事务回滚时能够撤销所有已经成功执⾏的 sql语句,他需要记录你要回滚的相应⽇志信息

当做数据修改的时候,不仅在内存中操作,还会 在 redo log 中记录这次操作。当事务提交的时候,会将 redo log ⽇志进⾏刷盘(redo log⼀部 分在内存中,⼀部分在磁盘上)。

MVCC 旨在控制多版本并发读写,维持一个数据的多个版本,使得读-写操作没有冲突。是一种用来解决读-写冲突的无锁并发控制 MVCC 是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销。

只有写写操作是阻塞的;
在这里插入图片描述
链接

[88]Mysql 怎么保证⼀致性的?

(原⼦性、隔离性、持久性和应⽤层代码判断)
在这里插入图片描述
在这里插入图片描述

[89]讲⼀下索引及其底层,⾮叶⼦节点存储的是什么,只有b+树索引吗?(MEMORY是hash 索引索引是为了快速查找数据,就跟⼀本书的⽬录⼀样。在⽬录中检索到具体章节的⻚码,然后直 接跳转,就相当于根据索引快速找到数据在磁盘上的地址,然后去读取数据。 MySQL数据库索引采⽤的是B+Tree结构,在B-Tree结构上做了优化改造。

(1)B-Tree结构 1. 索引值和data数据分布在整棵树结构中 2. 每个节点可以存放多个索引值及对应的data数据 3. 树节点中的多个索引值从左到右升序排列
(2)B+Tree结构: 1. ⾮叶⼦节点不存储data数据,只存储索引值,这样便于存储更多的索引值 2. 叶⼦节点包含了所有的索引值和data数据 3. 叶⼦节点⽤指针连接,提⾼区间的访问性能
在这里插入图片描述
1)B树
B树中每个节点包含了键值和键值对于的数据对象存放地址指针,所以成功搜索一个对象可以不用到达树的叶节点。
2)B+树
B+树非叶节点中存放关键码。所有的叶节点在同一层上,包含了全部关键码和相应数据对象的存放地址指针,且叶节点按关键码从小到大顺序链接。如果实际数据对象按加入的顺序存储而不是按关键码次数存储的话,叶节点的索引必须是稠密索引,若实际数据存储按关键码次序存放的话,叶节点索引时稀疏索引。
在这里插入图片描述
B+树的高度一般不超过3

红黑数、平衡树适用于内存中的少量的数据;B+树适合于数据库中大量的树

在这里插入图片描述

[90]Mysql存储引擎的作⽤

存储引擎负责MySQL中数据的存储和提取

[91]Mysql工作流程

在这里插入图片描述

[92]事务可以嵌套吗

可以,因为嵌套事务也是众多事务分类中的一种,它是一个层次结构框架。有一个顶层事务控制着各个层次的事务,顶层事务之下嵌套的事务被称为子事务,它控制每一个局部的变换。
需要注意的是,MySQL数据库不支持嵌套事务。

[93]如何实现可重复读?

为了实现可重复读,MySQL 采用了 MVVC (多版本并发控制) 的方式。
我们在数据库表中看到的一行记录可能实际上有多个版本,每个版本的记录除了有数据本身外,还要有一个表示版本的字段,记为 row trx_id,而这个字段就是使其产生的事务的 id,事务 ID 记为 transaction id,它在事务开始的时候向事务系统申请,按时间先后顺序递增。

可重复读是在事务开始的时候生成一个当前事务全局性的快照。对于一个快照来说,它能够读到那些版本数据,要遵循以下规则:
当前事务内的更新,可以读到;
版本未提交,不能读到;
版本已提交,但是却在快照创建后提交的,不能读到;
版本已提交,且是在快照创建前提交的,可以读到。

[94]如何解决幻读问题?

RR级别下的MVCC解决不了幻读问题,只能在一定程度下缓解幻读问题
InnoDB存储引擎在REPEATABLE READ事务隔离级别下,使用Next-Key Lock的锁算法,因此避免了幻读的产生。 MySQL 把行锁和间隙锁合并在一起,解决了并发写和幻读的问题,这个锁叫做 Next-Key锁。

[95]MySQL事务如何回滚?

在MySQL默认的配置下,事务都是自动提交和回滚的。当显示地开启一个事务时,可以使用ROLLBACK语句进行回滚。该语句有两种用法:

ROLLBACK:要使用这个语句的最简形式,只需发出ROLLBACK。同样地,也可以写为ROLLBACK WORK,但是二者几乎是等价的。回滚会结束用户的事务,并撤销正在进行的所有未提交的修改。

ROLLBACK to [SAVEPOINT] identifier :这个语句与SAVEPOINT命令一起使用。可以把事务回滚到标记点,而不回滚在此标记点之前的任何工作。

[96] 了解数据库的锁吗?

锁是数据库系统区别于文件系统的一个关键特性,锁机制用于管理对共享资源的并发访问。下面我们以MySQL数据库的InnoDB引擎为例,来说明锁的一些特点。

1锁的类型:
InnoDB存储引擎实现了如下两种标准的行级锁:
共享锁(S Lock),允许事务读一行数据。
排他锁(X Lock),允许事务删除或更新一行数据。
2.锁的粒度:行锁、页面锁 表锁
3. 锁的算法
Record Lock:单个行记录上的锁。,锁定记录本身
Gap Lock:间隙锁,锁定一个范围,但不包含记录本身。它的作用是为了阻止多个事务将记录插入到同一范围内,而这会导致幻读问题的产生
Next-Key Lock∶Gap Lock+Record Lock,锁定一个范围,并且锁定记录本身。

4死锁:死锁是指两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一
种互相等待的现象。若无外力作用,事务都将无法推进下去。

解决死锁方法:
1.超时,即当两个事务互相等待时,当一个等待时间超过设置的某一阈值时,其中一个事务进行回滚,另一个等待的事务就能继续进行。
2.用wait-for graph(等待图)的方式来进行死锁检测。wait-for graph要求数据库保存以下两种信息:锁的信息链表;事务等待链表;在这个图中若存在回路,就代表存在死锁,因此资源间相互发生等待
锁的升级:将当前锁的粒度降低。举例来说,数据库可以把一个表的1000个行锁升级为一个页锁,或者将页锁升级为表锁。
InnoDB存储引擎不存在锁升级的问题。因为其不是根据每个记录来产生行锁的,相反,其根据每个事务访问的每个页对锁进行管理的,采用的是位图的方式。因此不管一个事务锁住页中一个记录还是多个记录,其开销通常都是一致的。

[97] InnoDB中行级锁是怎么实现的?

InnoDB行级锁是通过给索引上的索引项加锁来实现的。只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁。
当表中锁定其中的某几行时,不同的事务可以使用不同的索引锁定不同的行。另外,不论使用主键索引、唯一索引还是普通索引,InnoDB都会使用行锁来对数据加锁。

[98]使用表锁情况

(1)表⽐较⼤,事务需要更新全部或者⼤部分数据
(2)事务涉及到多个表,⽐较复杂,可能引起死锁,造成⼤ᰁ的事务回滚

[99]无锁队列

无锁队列用在什么样的场景
当需要处理的数据非常多,比如行情数据,一秒处理非常多的数据的时候,可以考虑用无锁队列。数据量相对少的时候用互斥锁。(一)yqueue——无锁队列

[100]数据库在什么情况下会发生死锁?

死锁是指两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种互相等待的现象。若无外力作用,事务都将无法推进下去。下图演示了死锁的一种经典的情况,即A等待B、B等待A,这种死锁问题被称为AB-BA死锁。

[续]C++岗位求职面试八股文第二十二篇(数据库)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT与Fintech

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值