常规数据库面试题

1.事务的4大特性?
原子性:一个事务是一个基本工作单元,不能分割。所以,结果是要么执行完成,要么不做。

一致性:事务执行的前后数据的状态是一致。

隔离性:事务之间不会相互影响

持久性:数据的变更是持久的。即使数据库宕机也不影响。

2.事务的隔离等级
a. read uncommited :会出现脏读,不可重复读,幻读
b. read committed:会出现不可重复读和幻读
c. repeatable read:会出现幻读,但是可以使用select...for update解决
d. serializable :3个问题都解决

后面又多了一个快照的隔离级别:Snapshot Isolation

不考虑事务的隔离级别,会出现以下错误的情况
· 脏读:一个线程中的事务读到了另外一个线程中未提交update的数据。
· 不可重复读:一个线程中的事务读到了另外一个线程中已经提交的update的数据。
·虚读:一个线程中的事务读到了另外一个线程中已经提交的insert的数据。

对幻读的理解:

有争执:

正常的理解:

当某个事务在读取某个范围的记录的时候,另外一个事务又在该范围插入了新的记录,当前事务再次读取这个范围的记录,会产生幻行(Phantom Data)。 -- 简单说:就是两次select出现的数据范围不一样。

现在争论的点就是:对于查询-插入的的场景,出现的问题是查询不到,但是又插入不了(因为加了唯一索引)。这种情况算不算幻读。

个人觉得不重要,重要的是会不会产生问题。我认为,查询-插入的的场景,不算是问题,就像是多了db层的一个校验,防止产出业务语义重复的数据。

serializable通过加读锁的方式解决了幻读的问题,但是这样锁冲突的概率会比较高,一般不会用。

参考:图解mysql事务的四个隔离级别 - 墨天轮

MySQL中的幻读,你真的理解吗? - 云+社区 - 腾讯云

关于幻读,可重复读的真实用例是什么? - 知乎 这个理解更到位。使用多版本并发控制解决幻读问题。

oracle默认的隔离级别是repeatable read,一个线程在事务开始时,可以取到库中所有表的瞬时状态,读取到的数据是当前SCN(系统改变号)下的数据,在事务的过程中不会读取到其他线程对表的改变。

这样数据库存在一个高并发问题,一个i线程在先select得到A, 休眠10秒,再将A=A+1,写入到数据库中, 有另外一个线程j在i线程休眠期间,将数据库中的A值改成A+2。

那么数据库最终的结果就是,j线程对表的操作丢失。

在mysql中行锁需要由insert语句来触发,仅仅是事务开启和select操作是不能触发行锁的。

Oracle是否可以默认通过乐观锁的机制防止者中情况的发生呢,需要实验下。

select for update 操作的列 会加上读写锁。在加锁的线程执行commit操作之前,其它线程对加锁行的select for updae和写操作需要等待,但是如果只是普通的select是不会等待的。 但是对空记录是不能加锁的。

select for update 加锁的记录是事务之间立即可见的。

总结:数据库的事务机制,不能解决高并发下数据丢失的问题。这就是redis锁存在的意义。

3. 事务的传播属性
事务的传播属性分为7种:粗略的分可以分为3大类别:方法一定要在事务中进行,方法可以在也可以不在事务中进行,方法一定不在事务中进行。
默认是required,一定要在事务中进行,如果事务不存在,则需新建一个事务。
另外几种类型:
1. mandatory,必须在事务中进行,事务不存在则抛出异常
2. required_new, 启动一个新的事务执行方法,如果存在当前事务,则将当前事务挂起
3. supported,存在事务则在事务中进行,不存在事务则不在事务中进行
4. never,方法不能再事务中进行,如果存在事务则抛出异常    
5. not_support, 不能在事务中进行,如果存在事务,则将事务挂起
6. nest,嵌套事务。嵌套事务发生异常时,只回滚嵌套事务。不会回滚主事务。实现原理:嵌套事务生成时,相当于是新建了一个savepoint。

4. 数据库3大范式

a.列不可分,列的设计要保持原子性。有时候也会违背,比如说值对象

b. 表中的列,需要和主键有关联。一个表应该存储一个实体的属性,不要存放其它实体的属性。
c. 要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。表之间不要存在冗余信息,通过外键关联查询即可,最好还是不要违背,冗余信息维护起来很麻烦。如果查询一定需要,那就分两张表查吧。

5. 数据库索引的原理

参考博文:数据库索引原理 - konglingbin - 博客园

Mysql中的B+树:和B树对比,它在叶子节点之间加了双向列表,叶子节点的数据块之间可以相互访问,减少了索引时间和io时间(包括磁道寻址时间,旋转时间,传输时间,每次在10毫秒左右)。

Oracle中的B*树:与B+树的区别,非叶子节点间增加了双向链表相互连接

裂变的方式不一样:

B+树:当节点满时,创建一个新节点,将原节点中1/2的数据放到新节点

B*树:当节点满时,向考虑将数据放到兄弟节点中,如果说兄弟节点也满了,再考虑创建一个新节点,再将原节点1/3的数据放到新节点中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值