MySQL 常见面试题/知识点总结!(2021 最新版)| JavaGuide

相关阅读: 2.7w字!Java基础面试题/知识点总结!(2021 最新版)mysql

这篇文章以前发过,不过,我最近对其进行了重构完善而且修复了不少小问题。因此,在再同步一下!git

内容很硬!强烈建议小伙伴们花 10 分钟左右阅读一遍!程序员

MySQL 基础

关系型数据库介绍

顾名思义,关系型数据库就是一种创建在关系模型的基础上的数据库。关系模型代表了数据库中所存储的数据之间的联系(一对1、一对多、多对多)。github

关系型数据库中,咱们的数据都被存放在了各类表中(好比用户表),表中的每一行就存放着一条数据(好比一个用户的信息)。面试

大部分关系型数据库都使用 SQL 来操做数据库中的数据。而且,大部分关系型数据库都支持事务的四大特性(ACID)。算法

有哪些常见的关系型数据库呢?sql

MySQL、PostgreSQL、Oracle、SQL Server、SQLite(微信本地的聊天记录的存储就是用的 SQLite) ......。数据库

MySQL 介绍

MySQL 是一种关系型数据库,主要用于持久化存储咱们的系统中的一些数据好比用户信息。缓存

因为 MySQL 是开源免费而且比较成熟的数据库,所以,MySQL 被大量使用在各类系统中。任何人均可以在 GPL(General Public License) 的许可下下载并根据个性化的须要对其进行修改。MySQL 的默认端口号是3306安全

存储引擎

存储引擎相关的命令

查看 MySQL 提供的全部存储引擎

mysql> show engines;
复制代码

查看MySQL提供的全部存储引擎

从上图咱们能够查看出 MySQL 当前默认的存储引擎是 InnoDB,而且在 5.7 版本全部的存储引擎中只有 InnoDB 是事务性存储引擎,也就是说只有 InnoDB 支持事务。

查看 MySQL 当前默认的存储引擎

咱们也能够经过下面的命令查看默认的存储引擎。

mysql> show variables like '%storage_engine%';
复制代码

查看表的存储引擎

show table status like "table_name" ;
复制代码

查看表的存储引擎

MyISAM 和 InnoDB 的区别

MySQL 5.5 以前,MyISAM 引擎是 MySQL 的默认存储引擎,可谓是风光一时。

虽然,MyISAM 的性能还行,各类特性也还不错(好比全文索引、压缩、空间函数等)。可是,MyISAM 不支持事务和行级锁,并且最大的缺陷就是崩溃后没法安全恢复。

5.5 版本以后,MySQL 引入了 InnoDB(事务性数据库引擎),MySQL 5.5 版本后默认的存储引擎为 InnoDB。小伙子,必定要记好这个 InnoDB ,你每次使用 MySQL 数据库都是用的这个存储引擎吧?

言归正传!我们下面仍是来简单对比一下二者:

1.是否支持行级锁

MyISAM 只有表级锁(table-level locking),而 InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁。

也就说,MyISAM 一锁就是锁住了整张表,这在并发写的状况下是多么滴憨憨啊!这也是为何 InnoDB 在并发写的时候,性能更牛皮了!

2.是否支持事务

MyISAM 不提供事务支持。

InnoDB 提供事务支持,具备提交(commit)和回滚(rollback)事务的能力。

3.是否支持外键

MyISAM 不支持,而 InnoDB 支持。

🌈 拓展一下:

通常咱们也是不建议在数据库层面使用外键的,应用层面能够解决。不过,这样会对数据的一致性形成威胁。具体要不要使用外键仍是要根据你的项目来决定。

4.是否支持数据库异常崩溃后的安全恢复

MyISAM 不支持,而 InnoDB 支持。

使用 InnoDB 的数据库在异常崩溃后,数据库从新启动的时候会保证数据库恢复到崩溃前的状态。这个恢复的过程依赖于 redo log

🌈 拓展一下:

  • MySQL InnoDB 引擎使用 redo log(重作日志) 保证事务的持久性,使用 undo log(回滚日志) 来保证事务的原子性
  • MySQL InnoDB 引擎经过 锁机制MVCC 等手段来保证事务的隔离性( 默认支持的隔离级别是 REPEATABLE-READ )。
  • 保证了事务的持久性、原子性、隔离性以后,一致性才能获得保障。

5.是否支持 MVCC

MyISAM 不支持,而 InnoDB 支持。

讲真,这个对比有点废话,毕竟 MyISAM 连行级锁都不支持。

MVCC 能够看做是行级锁的一个升级,能够有效减小加锁操做,提供性能。

关于 MyISAM 和 InnoDB 的选择问题

大多数时候咱们使用的都是 InnoDB 存储引擎,在某些读密集的状况下,使用 MyISAM 也是合适的。不过,前提是你的项目不介意 MyISAM 不支持事务、崩溃恢复等缺点(但是~咱们通常都会介意啊!)。

《MySQL 高性能》上面有一句话这样写到:

不要轻易相信“MyISAM 比 InnoDB 快”之类的经验之谈,这个结论每每不是绝对的。在不少咱们已知场景中,InnoDB 的速度均可以让 MyISAM 可望不可即,尤为是用到了聚簇索引,或者须要访问的数据均可以放入内存的应用。

通常状况下咱们选择 InnoDB 都是没有问题的,可是某些状况下你并不在意可扩展能力和并发能力,也不须要事务支持,也不在意崩溃后的安全恢复问题的话,选择 MyISAM 也是一个不错的选择。可是通常状况下,咱们都是须要考虑到这些问题的。

所以,对于我们平常开发的业务系统来讲,你几乎找不到什么理由再使用 MyISAM 做为本身的 MySQL 数据库的存储引擎。

锁机制与 InnoDB 锁算法

MyISAM 和 InnoDB 存储引擎使用的锁:

  • MyISAM 采用表级锁(table-level locking)。
  • InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁

表级锁和行级锁对比:

  • 表级锁: MySQL 中锁定 粒度最大 的一种锁,对当前操做的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定粒度最大,触发锁冲突的几率最高,并发度最低,MyISAM 和 InnoDB 引擎都支持表级锁。
  • 行级锁: MySQL 中锁定 粒度最小 的一种锁,只针对当前操做的行进行加锁。 行级锁能大大减小数据库操做的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。

InnoDB 存储引擎的锁的算法有三种:

  • Record lock:记录锁,单个行记录上的锁
  • Gap lock:间隙锁,锁定一个范围,不包括记录自己
  • Next-key lock:record+gap 临键锁,锁定一个范围,包含记录自己

查询缓存

执行查询语句的时候,会先查询缓存。不过,MySQL 8.0 版本后移除,由于这个功能不太实用

my.cnf 加入如下配置,重启 MySQL 开启查询缓存

query_cache_type=1
query_cache_size=600000
复制代码

MySQL 执行如下命令也能够开启查询缓存

set global query_cache_type=1;
set global query_cache_size=600000;
复制代码

如上,开启查询缓存后在一样的查询条件以及数据状况下,会直接在缓存中返回结果。这里的查询条件包括查询自己、当前要查询的数据库、客户端协议版本号等一些可能影响结果的信息。所以任何两个查询在任何字符上的不一样都会致使缓存不命中。此外,若是查询中包含任何用户自定义函数、存储函数、用户变量、临时表、MySQL 库中的系统表,其查询结果也不会被缓存。

缓存创建以后,MySQL 的查询缓存系统会跟踪查询中涉及的每张表,若是这些表(数据或结构)发生变化,那么和这张表相关的全部缓存数据都将失效。

缓存虽然可以提高数据库的查询性能,可是缓存同时也带来了额外的开销,每次查询后都要作一次缓存操做,失效后还要销毁。 所以,开启查询缓存要谨慎,尤为对于写密集的应用来讲更是如此。若是开启,要注意合理控制缓存空间大小,通常来讲其大小设置为几十 MB 比较合适。此外,还能够经过 sql_cache 和 sql_no_cache 来控制某个查询语句是否须要缓存:

select sql_no_cache count(*) from usr;
复制代码

事务

何为事务?

一言蔽之,事务是逻辑上的一组操做,要么都执行,要么都不执行。

能够简单举一个例子不?

事务最经典也常常被拿出来讲例子就是转帐了。假如小明要给小红转帐 1000 元,这个转帐会涉及到两个关键操做就是:

  1. 将小明的余额减小 1000 元
  2. 将小红的余额增长 1000 元。

事务会把这两个操做就能够当作逻辑上的一个总体,这个总体包含的操做要么都成功,要么都要失败。

这样就不会出现小明余额减小而小红的余额却并无增长的状况。

何为数据库事务?

数据库事务在咱们平常开发中接触的最多了。若是你的项目属于单体架构的话,你接触到的每每就是数据库事务了。

平时,咱们在谈论事务的时候,若是没有特指分布式事务,每每指的就是数据库事务

那数据库事务有什么做用呢?

简单来讲:数据库事务能够保证多个对数据库的操做(也就是 SQL 语句)构成一个逻辑上的总体。构成这个逻辑上的总体的这些数据库操做遵循:要么所有执行成功,要么所有不执行

# 开启一个事务
START TRANSACTION;
# 多条 SQL 语句
SQL1,SQL2...
## 提交事务
COMMIT;
复制代码

另外,关系型数据库(例如:MySQLSQL ServerOracle 等)事务都有 ACID 特性:

事务的特性

何为 ACID 特性呢?

  1. 原子性Atomicity) : 事务是最小的执行单位,不容许分割。事务的原子性确保动做要么所有完成,要么彻底不起做用;
  2. 一致性Consistency): 执行事务先后,数据保持一致,例如转帐业务中,不管事务是否成功,转帐者和收款人的总额应该是不变的;
  3. 隔离性Isolation): 并发访问数据库时,一个用户的事务不被其余事务所干扰,各并发事务之间数据库是独立的;
  4. 持久性Durabilily): 一个事务被提交以后。它对数据库中数据的改变是持久的,即便数据库发生故障也不该该对其有任何影响。

数据事务的实现原理呢?

咱们这里以 MySQL 的 InnoDB 引擎为例来简单说一下。

MySQL InnoDB 引擎使用 redo log(重作日志) 保证事务的持久性,使用 undo log(回滚日志) 来保证事务的原子性

MySQL InnoDB 引擎经过 锁机制MVCC 等手段来保证事务的隔离性( 默认支持的隔离级别是 REPEATABLE-READ )。

保证了事务的持久性、原子性、隔离性以后,一致性才能获得保障。

并发事务带来哪些问题?

在典型的应用程序中,多个事务并发运行,常常会操做相同的数据来完成各自的任务(多个用户对同一数据进行操做)。并发虽然是必须的,但可能会致使如下的问题。

  • 脏读(Dirty read): 当一个事务正在访问数据而且对数据进行了修改,而这种修改尚未提交到数据库中,这时另一个事务也访问了这个数据,而后使用了这个数据。由于这个数据是尚未提交的数据,那么另一个事务读到的这个数据是“脏数据”,依据“脏数据”所作的操做多是不正确的。
  • 丢失修改(Lost to modify): 指在一个事务读取一个数据时,另一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,所以称为丢失修改。 例如:事务 1 读取某表中的数据 A=20,事务 2 也读取 A=20,事务 1 修改 A=A-1,事务 2 也修改 A=A-1,最终结果 A=19,事务 1 的修改被丢失。
  • 不可重复读(Unrepeatable read): 指在一个事务内屡次读同一数据。在这个事务尚未结束时,另外一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,因为第二个事务的修改致使第一个事务两次读取的数据可能不太同样。这就发生了在一个事务内两次读到的数据是不同的状况,所以称为不可重复读。
  • 幻读(Phantom read): 幻读与不可重复读相似。它发生在一个事务(T1)读取了几行数据,接着另外一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些本来不存在的记录,就好像发生了幻觉同样,因此称为幻读。

不可重复读和幻读区别:

不可重复读的重点是修改好比屡次读取一条记录发现其中某些列的值被修改,幻读的重点在于新增或者删除好比屡次读取一条记录发现记录增多或减小了。

事务隔离级别有哪些?

SQL 标准定义了四个隔离级别:

  • READ-UNCOMMITTED(读取未提交): 最低的隔离级别,容许读取还没有提交的数据变动,可能会致使脏读、幻读或不可重复读
  • READ-COMMITTED(读取已提交): 容许读取并发事务已经提交的数据,能够阻止脏读,可是幻读或不可重复读仍有可能发生
  • REPEATABLE-READ(可重复读): 对同一字段的屡次读取结果都是一致的,除非数据是被自己事务本身所修改,能够阻止脏读和不可重复读,但幻读仍有可能发生
  • SERIALIZABLE(可串行化): 最高的隔离级别,彻底服从 ACID 的隔离级别。全部的事务依次逐个执行,这样事务之间就彻底不可能产生干扰,也就是说,该级别能够防止脏读、不可重复读以及幻读

隔离级别 脏读 不可重复读 幻读
READ-UNCOMMITTED
READ-COMMITTED ×
REPEATABLE-READ × ×
SERIALIZABLE × × ×

MySQL 的默认隔离级别是什么?

MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。咱们能够经过SELECT @@tx_isolation;命令来查看,MySQL 8.0 该命令改成SELECT @@transaction_isolation;

mysql> SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
复制代码

这里须要注意的是:与 SQL 标准不一样的地方在于 InnoDB 存储引擎在 REPEATABLE-READ(可重读) 事务隔离级别下使用的是 Next-Key Lock 锁算法,所以能够避免幻读的产生,这与其余数据库系统(如 SQL Server)是不一样的。因此说 InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读) 已经能够彻底保证事务的隔离性要求,即达到了 SQL 标准的 SERIALIZABLE(可串行化) 隔离级别。

🐛 问题更正:MySQL InnoDB 的 REPEATABLE-READ(可重读)并不保证避免幻读,须要应用使用加锁读来保证。而这个加锁度使用到的机制就是 Next-Key Locks。

由于隔离级别越低,事务请求的锁越少,因此大部分数据库系统的隔离级别都是 READ-COMMITTED(读取提交内容) ,可是你要知道的是 InnoDB 存储引擎默认使用 REPEATABLE-READ(可重读) 并不会有任何性能损失。

InnoDB 存储引擎在 分布式事务 的状况下通常会用到 SERIALIZABLE(可串行化) 隔离级别。

🌈 拓展一下(如下内容摘自《MySQL 技术内幕:InnoDB 存储引擎(第 2 版)》7.7 章):

InnoDB 存储引擎提供了对 XA 事务的支持,并经过 XA 事务来支持分布式事务的实现。分布式事务指的是容许多个独立的事务资源(transactional resources)参与到一个全局的事务中。事务资源一般是关系型数据库系统,但也能够是其余类型的资源。全局事务要求在其中的全部参与的事务要么都提交,要么都回滚,这对于事务原有的 ACID 要求又有了提升。另外,在使用分布式事务时,InnoDB 存储引擎的事务隔离级别必须设置为 SERIALIZABLE。

后记

最后再推荐一个很是不错的 Java 教程类开源项目:JavaGuide 。我在大三开始准备秋招面试的时候,建立了 JavaGuide 这个项目。目前这个项目已经有 100k+的 star,相关阅读:《1049 天,100K!简单复盘!》

对于你学习 Java 以及准备 Java 方向的面试都颇有帮助!正如做者说的那样,这是一份:涵盖大部分 Java 程序员所须要掌握的核心知识的 Java 学习+面试指南!

相关推荐:

我是 Guide哥,拥抱开源,喜欢烹饪。开源项目 JavaGuide 做者,Github:Snailclimb - Overview 。将来几年,但愿持续完善 JavaGuide,争取可以帮助更多学习 Java 的小伙伴!共勉!凎!点击查看个人2020年工做汇报!

参考

相关文章
相关标签/搜索