相关阅读: 2.7w字!Java基础面试题/知识点总结!(2021 最新版)mysql
这篇文章以前发过,不过,我最近对其进行了重构完善而且修复了不少小问题。因此,在再同步一下!git
内容很硬!强烈建议小伙伴们花 10 分钟左右阅读一遍!程序员
顾名思义,关系型数据库就是一种创建在关系模型的基础上的数据库。关系模型代表了数据库中所存储的数据之间的联系(一对1、一对多、多对多)。github
关系型数据库中,咱们的数据都被存放在了各类表中(好比用户表),表中的每一行就存放着一条数据(好比一个用户的信息)。面试
大部分关系型数据库都使用 SQL 来操做数据库中的数据。而且,大部分关系型数据库都支持事务的四大特性(ACID)。算法
有哪些常见的关系型数据库呢?sql
MySQL、PostgreSQL、Oracle、SQL Server、SQLite(微信本地的聊天记录的存储就是用的 SQLite) ......。数据库
MySQL 是一种关系型数据库,主要用于持久化存储咱们的系统中的一些数据好比用户信息。缓存
因为 MySQL 是开源免费而且比较成熟的数据库,所以,MySQL 被大量使用在各类系统中。任何人均可以在 GPL(General Public License) 的许可下下载并根据个性化的须要对其进行修改。MySQL 的默认端口号是3306。安全
查看 MySQL 提供的全部存储引擎
mysql> show engines;
复制代码
从上图咱们能够查看出 MySQL 当前默认的存储引擎是 InnoDB,而且在 5.7 版本全部的存储引擎中只有 InnoDB 是事务性存储引擎,也就是说只有 InnoDB 支持事务。
查看 MySQL 当前默认的存储引擎
咱们也能够经过下面的命令查看默认的存储引擎。
mysql> show variables like '%storage_engine%';
复制代码
查看表的存储引擎
show table status like "table_name" ;
复制代码
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
。
🌈 拓展一下:
REPEATABLE-READ
)。5.是否支持 MVCC
MyISAM 不支持,而 InnoDB 支持。
讲真,这个对比有点废话,毕竟 MyISAM 连行级锁都不支持。
MVCC 能够看做是行级锁的一个升级,能够有效减小加锁操做,提供性能。
大多数时候咱们使用的都是 InnoDB 存储引擎,在某些读密集的状况下,使用 MyISAM 也是合适的。不过,前提是你的项目不介意 MyISAM 不支持事务、崩溃恢复等缺点(但是~咱们通常都会介意啊!)。
《MySQL 高性能》上面有一句话这样写到:
不要轻易相信“MyISAM 比 InnoDB 快”之类的经验之谈,这个结论每每不是绝对的。在不少咱们已知场景中,InnoDB 的速度均可以让 MyISAM 可望不可即,尤为是用到了聚簇索引,或者须要访问的数据均可以放入内存的应用。
通常状况下咱们选择 InnoDB 都是没有问题的,可是某些状况下你并不在意可扩展能力和并发能力,也不须要事务支持,也不在意崩溃后的安全恢复问题的话,选择 MyISAM 也是一个不错的选择。可是通常状况下,咱们都是须要考虑到这些问题的。
所以,对于我们平常开发的业务系统来讲,你几乎找不到什么理由再使用 MyISAM 做为本身的 MySQL 数据库的存储引擎。
MyISAM 和 InnoDB 存储引擎使用的锁:
表级锁和行级锁对比:
InnoDB 存储引擎的锁的算法有三种:
执行查询语句的时候,会先查询缓存。不过,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 元,这个转帐会涉及到两个关键操做就是:
事务会把这两个操做就能够当作逻辑上的一个总体,这个总体包含的操做要么都成功,要么都要失败。
这样就不会出现小明余额减小而小红的余额却并无增长的状况。
数据库事务在咱们平常开发中接触的最多了。若是你的项目属于单体架构的话,你接触到的每每就是数据库事务了。
平时,咱们在谈论事务的时候,若是没有特指分布式事务,每每指的就是数据库事务。
那数据库事务有什么做用呢?
简单来讲:数据库事务能够保证多个对数据库的操做(也就是 SQL 语句)构成一个逻辑上的总体。构成这个逻辑上的总体的这些数据库操做遵循:要么所有执行成功,要么所有不执行 。
# 开启一个事务
START TRANSACTION;
# 多条 SQL 语句
SQL1,SQL2...
## 提交事务
COMMIT;
复制代码
另外,关系型数据库(例如:MySQL
、SQL Server
、Oracle
等)事务都有 ACID 特性:
Atomicity
) : 事务是最小的执行单位,不容许分割。事务的原子性确保动做要么所有完成,要么彻底不起做用;Consistency
): 执行事务先后,数据保持一致,例如转帐业务中,不管事务是否成功,转帐者和收款人的总额应该是不变的;Isolation
): 并发访问数据库时,一个用户的事务不被其余事务所干扰,各并发事务之间数据库是独立的;Durabilily
): 一个事务被提交以后。它对数据库中数据的改变是持久的,即便数据库发生故障也不该该对其有任何影响。数据事务的实现原理呢?
咱们这里以 MySQL 的 InnoDB 引擎为例来简单说一下。
MySQL InnoDB 引擎使用 redo log(重作日志) 保证事务的持久性,使用 undo log(回滚日志) 来保证事务的原子性。
MySQL InnoDB 引擎经过 锁机制、MVCC 等手段来保证事务的隔离性( 默认支持的隔离级别是 REPEATABLE-READ
)。
保证了事务的持久性、原子性、隔离性以后,一致性才能获得保障。
在典型的应用程序中,多个事务并发运行,常常会操做相同的数据来完成各自的任务(多个用户对同一数据进行操做)。并发虽然是必须的,但可能会致使如下的问题。
不可重复读和幻读区别:
不可重复读的重点是修改好比屡次读取一条记录发现其中某些列的值被修改,幻读的重点在于新增或者删除好比屡次读取一条记录发现记录增多或减小了。
SQL 标准定义了四个隔离级别:
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
READ-UNCOMMITTED | √ | √ | √ |
READ-COMMITTED | × | √ | √ |
REPEATABLE-READ | × | × | √ |
SERIALIZABLE | × | × | × |
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年工做汇报!
《高性能 MySQL》