程序员的 MySQL 面试金典

在面试前,有一句话请记住:

获得高薪的关键:就是高效的准备面试

对于程序员来说,面试内容一般分为两个部分:

编程面试题部分 + 数据库面试题部分。

基于这个原则,我和汽车之家的资深技术专家老张,也是一位有着 10 年工作经验的技术老兵,前前后后大概花了两个多月的时间,改了 6 个版本,最终总结了 200 道左右的 MySQL 面试题,来帮助准备面试的朋友们。

对于技术面试来说,考察的核心包含以下两个特点:

  1. 考察的知识点广,因为不同的公司和不同的面试官技能知识结构是不同的,所以关注的问题和面试内容也是不同的,因而具备面试知识点广的特点;

  2. 考察的知识点较深入,以阿里巴巴为例,这些大厂的面试都是类似的,通常从一个大的面试点切入,然后层层深入,直到你不能接招为止。比如,你了解哪些数据库引擎?这个数据库引擎的特点是什么?这个数据库引擎是如何存储数据的?为什么要采用这种存储方式?等。

所以针对以上两个问题,我和老张结合自己 10 余年的工作和面试的经验,经过讨论和修改,最终制定了 8 大模块,汇总并介绍 MySQL 中的典型面试问题,它包含的内容如下:

  • 第一课时: 通用模块,此部分对 MySQL 整体概念、执行流程、数据库引擎、查询缓存、表空间、回表查询、数据类型间的区别、内存表、临时表、删除表的 n 种方式、枚举、视图、数据恢复等相关知识点对应的面试题进行解答。

  • 第二课时: 索引模块,索引的好坏直接影响数据库的性能,所以索引的面试题也是面试中必问的问题,此部分为索引对应的面试题合集。

  • 第三课时: 事务模块,事务决定了程序的稳定性,在 MySQL 中的地位也是首屈一指,也是面试中必问的面试题,此部分为事务对应的面试题合集。

  • 第四课时: 锁,锁包括:全局锁、表锁、行锁、死锁、乐观锁、悲观锁等,不同的数据库引擎支持的锁支持粒度也是不同的,此部分的面试题,让你彻底搞定锁相关的面试题。

  • 第五课时: 日志,日志看似不起眼,却是 MySQL 主备同步和容灾恢复以及问题排除的关键,当然也是面试中必问的问题,这部分会对不同的数据库引擎中的重点日志,进行详细的介绍。

  • 第六课时: MySQL 操作命令和内置函数,MySQL 的操作命令,对于程序员或者 DBA 来说也是必须具备的一项技能,比如,用户和权限的创建、数据库相关信息的查询等,都离不开对 MySQL 命令行的掌握。对内置函数的掌握程度,代表了你对 MySQL 的掌握程度,善用 MySQL 提供的内置函数,会让你有事半功倍的效果,内置函数也是笔试中必考的面试题。

  • 第七课时: 性能优化和分布式,性能优化和分布式是面试中决定你高度的关键指标,其中性能优化包括了慢查询的分析和处理,对分布式的掌握体现了你的技术深度。

  • 第八课时: 开放性问题,很多大公司最后也会问一下没有标准答案的开放性问题,以考察面试者的技术能力边界和对待问题的分析思路,这部分助你更平稳的获得 offer。

对应的知识图谱如下:

程序员的 MySQL 面试金典_第1张图片

作者介绍

程序员的 MySQL 面试金典_第2张图片老王:资深面试官/阿里云社区认证专家十余年编程从业经验,现上市公司技术研发经理,曾就职于 360,有着丰富的大型系统设计、开发和调优的经验,在不断探索和学习的过程中,积累了宝贵的编程与面试经验。

程序员的 MySQL 面试金典_第3张图片张建:十余年编程从业经验/现任上市公司项目经理曾就职新华保险通讯事业部、汽车之家。有着丰富的工业制造系统、呼叫中心、互联网系统设计、开发和调优经验。曾主导设计并参与了汽车之家二手车BU单体应用微服务化改造,有着丰富的微服务架构经验。

你能学到什么?

  • 扎实的 MySQL 基础:MySQL 内部执行流程、查询缓存、数据库引擎、表空间、表收缩、回表查询、删除数据恢复、视图、内存表和临时表的区别等。
  • 索引、事务、内置函数等模块的面试题汇总与解析。
  • 全局锁、表锁、行锁、死锁、乐观锁、悲观锁等面试题汇总与解析。
  • MySQL 中主从部署原理和容灾恢复的面试题和知识点解析。
  • MySQL 慢查询处理以及高性能方面的面试题汇总与解析。
  • MySQL 中开放性问题的汇总与解析。

适宜人群

  • 准备跳槽的后端工程师(初、中、高级)
  • 自学的准备转行的“准程序员”
  • 即将毕业的在校学生

购买须知

  • 本专栏为图文内容,共计 8 个课时;
  • 读者可在评论区向作者提问或交流;
  • 本课程可在 GitChat 服务号、APP 及网页端 gitbook.cn 上购买,一端购买,多端阅读。

课程内容

MySQL 事务的面试题总结

事务是什么?

事务是一系列的数据库操作,是数据库应用的基本单位。MySQL 事务主要用于处理操作量大,复杂度高的数据。

事务有哪些特性?

在 MySQL 中只有 InnDB 引擎支持事务,它的四个特性如下:

  • 原子性(Atomic):要么全部执行,要么全部不执行;
  • 一致性(Consistency):事务的执行使得数据库从一种正确状态转化为另一种正确状态;
  • 隔离性(Isolation):在事务正确提交之前,不允许把该事务对数据的任何改变提供给其他事务;
  • 持久性(Durability):事务提交后,其结果永久保存在数据库中。

MySQL 中有几种事务隔离级别?分别是什么?

MySQL 中有四种事务隔离级别,它们分别是:

  • read uncommited:未提交读,读到未提交数据;
  • read committed:读已提交,也叫不可重复读,两次读取到的数据不一致;
  • repetable read:可重复读;
  • serializable:串行化,读写数据都会锁住整张表,数据操作不会出错,但并发性能极低,开发中很少用到。

MySQL 默认使用 REPEATABLE-READ 的事务隔离级别。

幻读和不可重复读的区别?

  • 不可重复读的重点是修改:在同一事务中,同样的条件,第一次读的数据和第二次读的数据不一样。(因为中间有其他事务提交了修改)。
  • 幻读的重点在于新增或者删除:在同一事务中,同样的条件,,第一次和第二次读出来的记录数不一样。(因为中间有其他事务提交了插入/删除)。

并发事务一般有哪些问题?

  • 更新丢失(Lost Update):当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题,最后的更新覆盖了由其他事务所做的更新。例如,两个编辑人员制作了同一文档的电子副本,每个编辑人员独立地更改其副本,然后保存更改后的副本,这样就覆盖了原始文档。 最后保存其更改副本的编辑人员覆盖另一个编辑人员所做的更改,如果在前一个编辑人员完成并提交事务之前,另一个编辑人员不能访问同一文件,则可避免此问题。

  • 脏读(Dirty Reads):一个事务正在对一条记录做修改,在这个事务完成并提交前, 这条记录的数据就处于不一致状态; 这时, 另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些脏数据,并据此做进一步的处理,就会产生未提交的数据依赖关系,这种现象被形象地叫做脏读。

  • 不可重复读(Non-Repeatable Reads):一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!这种现象就叫做“不可重复读” 。

  • 幻读(Phantom Reads): 一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读” 。

并发事务有什么什么问题?应该如何解决?

并发事务可能造成:脏读、不可重复读和幻读等问题 ,这些问题其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决,解决方案如下:

  • 加锁:在读取数据前,对其加锁,阻止其他事务对数据进行修改。
  • 提供数据多版本并发控制(MultiVersion Concurrency Control,简称 MVCC 或 MCC),也称为多版本数据库:不用加任何锁, 通过一定机制生成一个数据请求时间点的一致性数据快照(Snapshot), 并用这个快照来提供一定级别 (语句级或事务级) 的一致性读取,从用户的角度来看,好象是数据库可以提供同一数据的多个版本。

什么是 MVCC?

MVCC 全称是多版本并发控制系统,InnoDB 和 Falcon 存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决幻读问题。

MVCC 是怎么工作的?

InnoDB 的 MVCC 是通过在每行记录后面保存两个隐藏的列来实现,这两个列一个保存了行的创建时间,一个保存行的过期时间(删除时间)。当然存储的并不是真实的时间而是系统版本号(system version number)。每开始一个新的事务,系统版本号都会自动新增,事务开始时刻的系统版本号会作为事务的版本号,用来查询到每行记录的版本号进行比较。

REPEATABLE READ(可重读)隔离级别下 MVCC 如何工作?

  • SELECT:InnoDB 会根据以下条件检查每一行记录:第一,InnoDB 只查找版本早于当前事务版本的数据行,这样可以确保事务读取的行要么是在开始事务之前已经存在要么是事务自身插入或者修改过的。第二,行的删除版本号要么未定义,要么大于当前事务版本号,这样可以确保事务读取到的行在事务开始之前未被删除。
  • INSERT:InnoDB 为新插入的每一行保存当前系统版本号作为行版本号。
  • DELETE:InnoDB 为删除的每一行保存当前系统版本号作为行删除标识。
  • UPDATE:InnoDB 为插入的一行新纪录保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为删除标识保存这两个版本号,使大多数操作都不用加锁。它不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作和一些额外的维护工作。

MySQL 事务实现原理是什么?

事务的实现是基于数据库的存储引擎,不同的存储引擎对事务的支持程度不一样。MySQL 中支持事务的存储引擎有InnoDB 和 NDB。InnoDB 是高版本 MySQL 的默认的存储引擎,因此就以 InnoDB 的事务实现为例,InnoDB 是通过多版本并发控制(MVCC,Multiversion Concurrency Control )解决不可重复读问题,加上间隙锁(也就是并发控制)解决幻读问题。因此 InnoDB 的 RR 隔离级别其实实现了串行化级别的效果,而且保留了比较好的并发性能。事务的隔离性是通过锁实现,而事务的原子性、一致性和持久性则是通过事务日志实现。

如何设置 MySQL 的事务隔离级别?

MySQL 事务隔离级别 MySQL.cnf 文件里设置的(默认目录 /etc/my.cnf),在文件的文末添加配置:

transaction-isolation = REPEATABLE-READ

可用的配置值:READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE。

InnoDB 默认的事务隔离级别是什么?如何修改?

InnoDB 默认的事务隔离是 repetable read(可重复读);可以通过 set 作用域 transaction isolation level 事务隔离级别 来修改事务的隔离级别,比如:

MySQL> set global transaction isolation level read committed; // 设置全局事务隔离级别为 read committed
MySQL> set session transaction isolation level read committed; // 设置当前会话事务隔离级别为 read committed

InnoDB 如何开启手动提交事务?

InnoDB 默认是自动提交事务的,每一次 SQL 操作(非 select 操作)都会自动提交一个事务,如果要手动开启事务需要设置 set autocommit=0 禁止自动提交事务,相当于开启手动提交事务。

在 InnoDB 中设置了 autocommit=0,添加一条信息之后没有手动执行提交操作,请问这条信息可以被查到吗?

autocommit=0 表示禁止自动事务提交,在添加操作之后没有进行手动提交,默认情况下其他连接客户端是查询不到此条新增数据的。

如何手动操作事务?

使用 begin 开启事务;rollback 回滚事务;commit 提交事务。具体使用示例如下:

begin;insert person(uname,age) values('laowang',18);rollback;commit;
MySQL 基础模块的面试题总结
MySQL 索引的面试题总结
MySQL 中锁的面试题总结
MySQL 中日志的面试题总结
MySQL 命令和内置函数
MySQL 性能优化 & 分布式
MySQL 常见的开放性问题

阅读全文: http://gitbook.cn/gitchat/column/5d80aea449b2b1063b52990f

你可能感兴趣的:(程序员的 MySQL 面试金典)