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:版本号如何实现? 【补充】
答:
-
获取当前version
-
if version = oldVersion, then set version = newVersion;
else update failed
-
核心SQL
update table set name = 'Aron', version = version + 1
where id = #{
id} and version = #{
version};
3、数据库死锁,如何防止?
答:
-
发生死锁情形
1)一个线程两次加锁;
2)两个线程互相申请对方的锁,但都不释放。 -
死锁产生必要条件 及 预防
1)互斥:一次只有一个进程可使用一个资源,其他进程不能访问已分配给其他进程的资源。
–>设备固有属性决定,不能改变。
2)占用且等待:当一个进程在等待分配得到其他资源时,其继续占有已分配得到的资源。
–>可以要求进程一次性请求所有需要的资源,比较低效。
3)非抢占:不能强行抢占进程中已占有的资源。
–> 如果占有某些资源的一个进程进一步资源请求被拒绝,则该进程必须释放最初占有资源。
–>如果一个进程请求当前被另一个进程占有的一个资源,则操作系统可以抢占另一个进程,要求它释放资源。
4)循环等待:存在一个封闭进程链,使得每个资源至少占有此链中下一个进程所需要的一个资源。
–>如果一个进程已经分配了R类资源,那么接下来请求资源只能是排在R类型之后的资源类型,比较低效。 -
处理死锁4种办法:死锁预防、检测、避免、解除。
办法 | 内容 |
---|---|
预防 | 破坏1个必要条件 |
检测 | 检查结构,及时清除 |
避免 | 进程启动拒绝、不允许分配【银行家算法】 |
解除 | 资源剥夺法、撤销进程法 |
4、数据库如何给一个范围加锁,有几种方法去解决幻读,MySQL 间隙锁(*2),实现方式。
4.1、幻读是什么?
答:幻读指一个事务两次查询同一个范围时,后一次看到了前一次没看到的行。
注意:
1)可重复读隔离级别下,普通查询是快照读,不会看到别的事务插入的数据。而幻读在“当前读”(能看到最新提交记录)下出现。
2)update的结果不能称为幻读,仅专指“新插入的行”。
4.2、幻读有什么问题?
1)语义一致性被破坏。行锁应该不准别的事务对锁住行进行读写操作,但新更新或插入到那行无法预防。
2)数据和日志在逻辑上的不一致性。
4.3、给所有的记录都加上锁,都阻止不了新插入的记录。那如何解决幻读呢?
答:幻读产生原因是,行锁只能锁住行,但新插入记录这个动作更新的是记录之间的“间隙”。为了解决幻读问题,InnoDB引入了间隙锁(Gap Lock)
间隙锁,锁的是两个值之间的空隙。比如,插入6个记录,就产生7个间隙。
间隙锁与读写锁不太一样,跟间隙锁存在冲突关系的,是“往这个间隙中插入一个记录”这个操作,间隙锁之间不存在冲突关系。
间隙锁和行锁合称为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、间隙锁会遇到死锁吗?缺点是什么?
答:会,下面例子会死锁。
缺点:间隙锁引入,可能导致同样语句锁住更大范围,影响并发度。
4.5、间隙锁的缺点有什么办法避免吗?
答:间隙锁是在可重复读隔离级别下才会生效的。所以,如果把隔离级别设置为读提交,就没有间隙锁了。但同时,你要解决可能出现的数据和日志不一致问题,需要把 binlog 格式设置为 row。
4.6、这又会带来什么问题?
答:根据具体业务需求进行分析,有待进一步理解与深入。……
五、参考
1、MongoDB 存储引擎:WiredTiger和In-Memory
2、《深入浅出MySQL》–第7章 表类型(存储引擎)的选择
3、乐观锁、悲观锁,这一篇就够了!
4、面试必备之乐观锁与悲观锁
5、【BAT面试题系列】面试官:你了解乐观锁和悲观锁吗?
6、死锁四个必要条件及死锁的预防、检测、避免、解除
7、死锁的产生、防止、避免、检测和解除
8、20 | 幻读是什么,幻读有什么问题?