【面试】数据库进阶篇(二)

0、问题纲要

3、存储引擎

1、(MySQL)存储引擎(*3)及区别(*2);InnoDB和MyISAM的区别(*2);

2、MongDB存储引擎。

4、并发

1、锁作用;

2、悲观锁和乐观锁(*2)区别、实现和应用场景;
 - 追问1:CAS是什么,导致的问题和解决方案? 【补充】
 - 追问2:版本号如何实现? 【补充】

3、数据库死锁(*2),如何防止?

4、数据库如何给一个范围加锁,有几种方法去解决幻读?MySQL 间隙锁(*2),实现方式

5、锁实现?

6、手里同时有两个任务,如何处理?

三、存储引擎

1、(MySQL)存储引擎(*3)及区别(*2);InnoDB和MyISAM的区别(*2)

特点 MyISAM InnoDB MEMORY
事务安全 & 外键 N Y N
锁机制 表锁 行锁 表锁
- - - -
优势 访问速度快,适合以SELECT、INSERT为主应用 支持外键、事务完整性、并发一致性等 内存存放,默认hash索引,可快速定位记录
缺点 事务完整性、并发性不适合 一旦服务关闭,表中数据丢掉。安全性低
场景 Web、数据仓库 计费、财务系统 更新不频繁的小表(要确保数据库异常可以恢复)

2、MongDB存储引擎。

特点 WiredTiger inMemory
持久化 存到Disk Files中 存到Cache中
并发 大多数读写操作使用乐观并发控制 文件级别并发控制,多个写操作同一个文档必须以序列化方式执行
异常/崩溃 通过日志文件可还原到Checkpoint操作之后发生的数据更新 数据会丢失

四、并发

1、锁作用?

答:数据库锁是为了正确地并发访问多用户共享资源,合理设置访问资源的规则。

2、悲观锁和乐观锁(*2)区别和应用场景;

类型 乐观锁 悲观锁
概念 先用,实际更新时再判断数据是否更新过,没有表示成功,否则回滚重试。 先获取锁,再进行业务操作。
实现 版本号、CAS Java-synchronized(1.6后有偏向锁+轻量级锁优化); MySQL-读锁、写锁、行锁
场景 读多写少 读少写多
追问1:CAS是什么,导致的问题和解决方案? 【补充】

1.1)CAS是什么?

答:CAS 操作中包含三个操作数: 
  - 需要读写的内存位置V 
  - 进行比较的预期原值A 
  - 拟写入的新值B

  if isMatched(V, A)  then A=B 
  else then A不变 

1.2)CAS会导致什么问题?
答:ABA 问题、循环时间长开销大、只能保证一个共享变量的原子操作

1.3)如何解决?
答:

问题 方案
ABA 引入版本号
开销大 退出机制:设置重试次数/阈值
单共享变量 把多个共享变量合并成一个,可以把多个变量放到一个对象[AtomicReference]
追问2:版本号如何实现? 【补充】

答:

  1. 获取当前version

  2. if version = oldVersion, then set version = newVersion;
    else update failed

  3. 核心SQL

update table set name = 'Aron', version = version + 1
where id = #{
    
    id} and version = #{
    
    version};

3、数据库死锁,如何防止?

答:

  1. 发生死锁情形
    1)一个线程两次加锁;
    2)两个线程互相申请对方的锁,但都不释放。

  2. 死锁产生必要条件 及 预防
    1)互斥:一次只有一个进程可使用一个资源,其他进程不能访问已分配给其他进程的资源。
    –>设备固有属性决定,不能改变。
    2)占用且等待:当一个进程在等待分配得到其他资源时,其继续占有已分配得到的资源。
    –>可以要求进程一次性请求所有需要的资源,比较低效。
    3)非抢占:不能强行抢占进程中已占有的资源。
    –> 如果占有某些资源的一个进程进一步资源请求被拒绝,则该进程必须释放最初占有资源。
    –>如果一个进程请求当前被另一个进程占有的一个资源,则操作系统可以抢占另一个进程,要求它释放资源。
    4)循环等待:存在一个封闭进程链,使得每个资源至少占有此链中下一个进程所需要的一个资源。
    –>如果一个进程已经分配了R类资源,那么接下来请求资源只能是排在R类型之后的资源类型,比较低效。

  3. 处理死锁4种办法:死锁预防、检测、避免、解除。

办法 内容
预防 破坏1个必要条件
检测 检查结构,及时清除
避免 进程启动拒绝、不允许分配【银行家算法】
解除 资源剥夺法、撤销进程法

4、数据库如何给一个范围加锁,有几种方法去解决幻读,MySQL 间隙锁(*2),实现方式。

4.1、幻读是什么?

答:幻读指一个事务两次查询同一个范围时,后一次看到了前一次没看到的行。
注意:
1)可重复读隔离级别下,普通查询是快照读,不会看到别的事务插入的数据。而幻读在“当前读”(能看到最新提交记录)下出现。
2)update的结果不能称为幻读,仅专指“新插入的行”。

4.2、幻读有什么问题?

1)语义一致性被破坏。行锁应该不准别的事务对锁住行进行读写操作,但新更新或插入到那行无法预防。
2)数据和日志在逻辑上的不一致性。

4.3、给所有的记录都加上锁,都阻止不了新插入的记录。那如何解决幻读呢?

答:幻读产生原因是,行锁只能锁住行,但新插入记录这个动作更新的是记录之间的“间隙”。为了解决幻读问题,InnoDB引入了间隙锁(Gap Lock)
间隙锁,锁的是两个值之间的空隙。比如,插入6个记录,就产生7个间隙。
1

间隙锁与读写锁不太一样,跟间隙锁存在冲突关系的,是“往这个间隙中插入一个记录”这个操作,间隙锁之间不存在冲突关系。
间隙锁和行锁合称为next-key lock,每个next-key lock是前开后闭区间。如果把select * from t for update把整个表所有记录锁起来,就形成了7个next-key lock,分别是(-∞,0]、(0,5]、(5,10]、(10,15]、(15,20]、(20, 25]、(25, +supremum]。

注:这里把间隙锁记为开区间,把 next-key lock 记为前开后闭区间。

4.4、间隙锁会遇到死锁吗?缺点是什么?

答:会,下面例子会死锁。
2

缺点:间隙锁引入,可能导致同样语句锁住更大范围,影响并发度。

4.5、间隙锁的缺点有什么办法避免吗?

答:间隙锁是在可重复读隔离级别下才会生效的。所以,如果把隔离级别设置为读提交,就没有间隙锁了。但同时,你要解决可能出现的数据和日志不一致问题,需要把 binlog 格式设置为 row。

4.6、这又会带来什么问题?

答:根据具体业务需求进行分析,有待进一步理解与深入。……

五、参考

1、MongoDB 存储引擎:WiredTiger和In-Memory
2、《深入浅出MySQL》–第7章 表类型(存储引擎)的选择
3、乐观锁、悲观锁,这一篇就够了!
4、面试必备之乐观锁与悲观锁
5、【BAT面试题系列】面试官:你了解乐观锁和悲观锁吗?
6、死锁四个必要条件及死锁的预防、检测、避免、解除
7、​死锁的产生、防止、避免、检测和解除
8、20 | 幻读是什么,幻读有什么问题?

猜你喜欢

转载自blog.csdn.net/HeavenDan/article/details/111935985