今日语录:“没有执行力,就没有竞争力 ”
参考资料:图解MySQL、MySQL面试题
1、事务有哪些特性?
原子性:
- 一个事务中的所有操作,要么全部完成,要么全部不完成,不会出现某个中间状态。如果在事务执行过程中发生了错误,那么事务就会进行回滚,就好像什么都没有发生过一样。
一致性:
- 是指事务操作前和事务操作后,数据库中的数据保持一致性的状态。比如事务发生前,A和B的总金额是1200元,那么事务发生后,两者的总金额还是1200元。
隔离性:
- 数据库允许多个并发事务同时对数据进行修改,隔离性保证了并发事务由于交叉修改数据而导致的数据的不一致问题。
持久性:
- 事务一旦执行完成,那么对数据库中的数据所做的修改就是永久性的。
持久性是通过redo log来实现的。
原子性是通过undo log来实现的。
隔离性是通过MVCC或者锁机制来实现的。
一致性是通过持久性、原子性以及隔离性来实现的。
2、并行事务会导致什么样的问题?
并行事务会导致脏读、不可重复读以及幻读。
- 脏读:一个事务读到了另一个未提交事务所修改的数据。
- 不可重复读:在一个事务内多次读取同一个数据,出现了前后两次读到的数据不一致的情况。
- 幻读:在一个事务内多次查询符合某个查询条件的 记录数量,出现了前后两次查询到的记录数量不一致的情况。
3、事物的隔离级别有哪些?分别解决了哪些问题?
事务的隔离级别有四个:分别是读未提交、读提交、可重复读以及串行化。
- 读未提交:一个事务在未提交时所作的变更就能被其他事务所看到(可能发生脏读、不可重复读以及幻读)
- 读提交:一个事务只有在提交之后,它所作的变更才能被其他事务所看到(可能发生不可重复读以及幻读)
- 可重复读:一个事务执行过程中所看到的数据,跟这个事务启动时所看到的数据是一致的,是MySQL innoDB默认的隔离级别(可能发生幻读,但是可以在很大程度上避免幻读)
- 串行化:对记录进行加锁,在多个事务对记录进行读写时,如果发生了冲突,那么后访问的事务必须要等待先访问的事务执行完成 (脏读、不可重复读以及幻读都不会发生)
4、可重复读隔离级别是如何在很大程度上避免幻读的?
可重复读隔离级别分别针对快照读和当前读提出了两种解决方案。
- 针对快照读(普通的select语句):通过MVCC(多版本并发控制)来解决,当一个事务开始之后,生成一个Read View,然后整个事务运行期间都使用这个Read View。
- 针对当前读(select ... for update):通过记录锁+间隙锁(next-key lock)来解决,它会对某个范围进行加锁,如果在查询期间,某个事物在已锁定范围内插入数据,那么就会导致插入失败。
5、谈谈你对MVCC的理解?⭐
MVCC是由undo log和Read View共同实现的
undo log记录的是事务更新前的数据:
- 比如在插入一条数据时,记录这条数据的主键值,回滚时直接根据主键值进行删除;
- 比如在修改一条数据时,记录原来的数据,回滚时,按照原来的数据进行回滚
- 每次执行事务时,都会生成一条undo log,undo log通过roll_pointer指针串联起来,这条链表就叫做版本链;
Read View相当于数据快照,它管理了一个事务列表,可以根据记录的trx_id事务id来控制这条记录对当前事务来说是否可见。
6、undo log、redo log以及bin log各自有什么作用?⭐
undo log:
- 用来撤销回退,undo log记录了更新前的数据,事务执行过程出现问题可以根据历史数据进行回滚;undo log实现了事务的原子性,并和Read View一起实现了MVCC(多版本并发控制)
redo log:
- redo log是物理日志,主要记录了事务对记录所做的修改;当事务在执行过程中对数据进行修改时,会先修改Buffer pool中的页,并将其设置为脏页,但是这些脏页不会马上被刷新到磁盘,而是由后台线程选择合适的时机进行刷新;Buffer pool是内存中的一块区域,为了避免掉电等故障导致内存中的数据丢失,所以用redo log来记录事务对数据做了什么修改,当事务提交时,只需要将redo log刷新到磁盘就可以了,之后即使掉电,数据库重启之后也可以根据redo log来对数据做还原。(redo log在写入磁盘时是顺序写,而buffer pool中的页写入到磁盘是随机写,顺序写比随机写的效率要高)
bin log:
- bin log是记录所有表结构变更和表数据修改的日志,主要用于备份恢复和主从复制;如果整个数据库的数据被删除了,只能利用bin log来进行恢复,redo log做不到。因为redo log在写的时候是循环写,边写边擦除;而bin log记录的是全量日志。
7、主从复制是怎么实现的?涉及到哪些线程?⭐
主从复制依赖于bin log实现,且主从复制是一个异步过程,主从复制的目的就是将主服务器的数据发送给从服务器
过程:
- 主服务器接收来自客户端的请求,将数据的变更操作写入bin log,然后提交事务,提交完成之后返回给客户端一个响应
- 从服务器创建一个I/O线程,连接主服务器的log dump线程,接收来自主服务器的bin log日志,并将其写入relay log的中继日志中
- 从服务器创建一个SQL线程,用来读取bin log日志并更新数据,达到主从服务器的数据一致的目的
8、事务有哪些状态?
- 活跃状态:事务正在执行中
- 部分提交状态:事务中的最后一条语句被执行完
- 失败状态:事务不能正常执行
- 提交状态:部分提交状态之后且数据往磁盘中写入完成
- 中止状态:事务出现错误回滚到事务开始之前的状态
9、count(*)、count(1)、count(主键字段)、count(字段)有什么区别?⭐
性能:count(*)= count(1)> count(主键字段)>count(字段)
count(主键字段):在只有聚簇索引的情况下,会遍历聚簇索引的B+树,每当读取到一条记录,就检查主键字段是否为null,不为null就将统计到的数量加1(如果有二级索引,优先遍历二级索引的B+树,因为二级索引的B+树相对于聚簇索引的B+树来说结构更简单)
count(1):在只有聚簇索引的情况下,同样遍历聚簇索引的B+树,每当读取到一条记录就将值加1(如果有二级索引,优先遍历二级索引的B+树,因为二级索引的B+树相对于聚簇索引的B+树来说结构更简单)
count(*):与count(1)执行过程基本一样
count(普通字段):进行全表扫描,每当读取到一条记录先检查普通字段是否为null,如果不为null将值加1
10、Buffer Pool有什么作用?
- Buffer Pool是一块连续的内存空间,它的作用是缓存数据,用来提高数据的读写性能。
- 当读取数据时,如果要读取的数据存在于buffer pool中,则直接从中读取,否则再到磁盘中读取。
- 当修改数据时,先修改buffer pool中的数据,然后将数据所在的页设置为脏页,然后由后台进程选择一个合适的时机将脏页刷新到磁盘中。
“今天也是元气满满的一天呐!”加油!
整理面经不易,如果对你有帮助的话点个赞吧