面试官:你说对MySQL事务很熟?那我问你10个问题

学习关系型数据库MySQL是很好的切入点,大部分人工做中用惯了CRUD,对面试官刨根问底的灵魂拷问你还能对答如流吗?咱们有必要了解一些更深层次的数据库基础原理。html

整理了面试中,关于MySQL事务和存储引擎10个FAQ(Frequently asked questions),你想知道的都在这里。mysql

什么是事务?

事务就是「一组原子性的SQL查询」,或者说一个独立的工做单元。若是数据库引擎可以成功地对数据库应用该组查询的所有语句,那么就执行该组查询。若是其中有任何一条语句由于崩溃或其余缘由没法执行,那么全部的语句都不会执行。也就是说,事务内的语句,要么所有执行成功,要么所有执行失败。git

事务控制语法知道吗?

BEGIN 或 START TRANSACTION 显式地开启一个事务;
COMMIT / COMMIT WORK两者是等价的。提交事务,并使已对数据库进行的全部修改为为永久性的;
ROLLBACK / ROLLBACK WORK。回滚会结束用户的事务,并撤销正在进行的全部未提交的修改;
SAVEPOINT identifier 在事务中建立一个保存点,一个事务中能够有多个 SAVEPOINT;
RELEASE SAVEPOINT identifier 删除一个事务的保存点;
ROLLBACK TO identifier 把事务回滚到标记点;
SET TRANSACTION 用来设置事务的隔离级别。InnoDB 存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE

用通俗的语言说说你理解的事务

用银行业务举个栗子,用户lemon有两银行卡,一张是招商银行CMBC的工资卡,另外一张是工商银行ICBC的储蓄卡,每个月5号发工资都要把招行卡的100万转到建设银行储蓄卡帐户。记住这里的银行缩写后面就是对应的数据表名称,你要记不住,我给你理一理。程序员

招商银行(CMBC):“存么?白痴!”
中国工商银行(ICBC): “爱存不存!”
中国建设银行(CCB): “存?存不?”
中国银行(BC): “不存!”
中国农业银行(ABC): “啊,不存!”
民生银行(CMSB):“存么?SB!"
兴业银行(CIB):“存一百。”
国家开发银行(CDB):“存点吧!”
汇丰银行(HSBC):“仍是不存!”

这个转帐的操做能够简化抽成一个事务,包含以下步骤:github

  1. 查询CMBC帐户的余额是否大于100万
  2. 从CMBC帐户余额中减去100万
  3. 在ICBC帐户余额中增长100万

如下语句对应建立了一个转帐事务:web

START TRANSACTION;
SELECT balance FROM CMBC WHERE username='lemon';
UPDATE CMBC SET balance = balance - 1000000.00 WHERE username = 'lemon';
UPDATE ICBC SET balance = balance + 1000000.00 WHERE username = 'lemon';
COMMIT;

事务的ACID特性是什么?

ACID实际上是事务特性的英文首字母缩写,具体的含义是这样的:面试

  • 原子性(atomicity)
    一个事务必须被视为一个不可分割的最小工做单元,整个事务中的全部操做要么所有提交成功,要么所有失败回滚,对于一个事务来讲,不可能只执行其中的一部分操做。
  • 致性(consistency)
    数据库老是从一个一致性的状态转换到另一个一致性的状态。在前面的例子中,一致性确保了,即便在执行第3、四条语句之间时系统崩溃,CMBC帐户中也不会损失100万,否则lemon要哭死由于事务最终没有提交,因此事务中所作的修改也不会保存到数据库中。
  • 隔离性(isolation)
    一般来讲,一个事务所作的修改在最终提交之前,对其余事务是不可见的。在前面的例子中,当执行完第三条语句、第四条语句还未开始时,此时若是有其余人也准备给lemon的CMBC帐户存钱,那他看到的CMBC帐户里仍是有100万的。
  • 持久性(durability)
    一旦事务提交,则其所作的修改就会永久保存到数据库中。此时即便系统崩溃,修改的数据也不会丢失。持久性是个有点模糊的概念,由于实际上持久性也分不少不一样的级别。有些持久性策略可以提供很是强的安全保障,而有些则未必。并且「不可能有能作到100%的持久性保证的策略」不然还须要备份作什么。

ACID

什么是脏读、不可重复读、幻读?

脏读

在事务A修改数据以后提交数据以前,这时另外一个事务B来读取数据,若是不加控制,事务B读取到A修改过数据,以后A又对数据作了修改再提交,则B读到的数据是脏数据,此过程称为脏读Dirty Read。redis

脏读

不可重复读

一个事务内在读取某些数据后的某个时间,再次读取之前读过的数据,却发现其读出的数据已经发生了变动、或者某些记录已经被删除了。sql

幻读

事务A在按查询条件读取某个范围的记录时,事务B又在该范围内插入了新的知足条件的记录,当事务A再次按条件查询记录时,会产生新的知足条件的记录(幻行 Phantom Row)
幻读shell

不可重复读与幻读有什么区别?

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

SQL的四个隔离级别知道吗?具体是什么解决了什么问题说说看

SQL实现了四个标准的隔离级别,每一种级别都规定了一个事务中所作的修改,哪些在事务内和事务间是可见的,哪些是不可见的。低级别的隔离级通常支持更高的并发处理,并拥有更低的系统开销。
隔离级别

各个隔离级别能够不一样程度的解决脏读、不可重复读、幻读。隔离级别各有所长,没有完美的解决方案,脱离业务场景谈具体实施都是耍流氓。

隔离级别对比

MySQL中哪些存储引擎支持事务?

MySQL中InnoDB和NDB Cluster存储引擎提供了事务处理能力,以及其余支持事务的第三引擎。

什么是自动提交?

MySQL默认采用自动提交AUTOCOMMIT模式。也就是说,若是不是显式地开始一个事务,则每一个查询都被看成一个事务执行提交操做。

对于MyISAM或者内存表这些事务型的表,修改AUTOCOMMIT不会有任何影响。对这类表来讲,没有COMMIT或者ROLLBACK的概念,也能够说是至关于一直处于AUTOCOMMIT启用的模式。

在事务中能够混合使用存储引擎吗?

尽可能不要再同一个事务中使用多种存储引擎,MySQL服务器层无论理事务,事务是由下层的存储引擎实现的。

若是在事务中混合使用了事务型和非事务型的表(例如InnoDB和MyISAM表),在正常提交的状况下不会有什么问题。

但若是该事务须要回滚,非事务型的表上的变动就没法撤销,这会致使数据库处于不一致的状态,这种状况很难修复,事务的最终结果将没法肯定。因此,为每张表选择合适的存储引擎很是重要。

MySQL存储引擎类型有哪些?

最经常使用的存储引擎是InnoDB引擎和MyISAM存储引擎,InnoDB是MySQL的默认事务引擎。

查看数据库表当前支持的引擎 :

show table status from 'your_db_name' where name='your_table_name'; 
查询结果表中的`Engine`字段指示存储引擎类型。

InnoDB存储引擎的特色和应用场景?

InnoDB是MySQL的默认「事务引擎」,被设置用来处理大量短时间(short-lived)事务,短时间事务大部分状况是正常提交的,不多会回滚。

更多InnoDB事务模型相关,参考MySQL官方手册,这里贴一下连接:https://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-model.html

历史

现代MySQL版本中的InnoDB在历史上叫InnoDB plugin,这个MySQL插件在2008年被开发出来,直到2010在Oracle收购了Sun公司后,发布的MySQL5.5才正式使用InnoDB plugin替代了旧版本的InnoDB,至此 「备胎」成功转正成为MySQL的御用引擎而再也不是插件,你看一个插件都这么努力。

特色

采用多版本并发控制(MVCC,MultiVersion Concurrency Control)来支持高并发。而且实现了四个标准的隔离级别,经过间隙锁next-key locking策略防止幻读的出现。

引擎的表基于聚簇索引创建,聚簇索引对主键查询有很高的性能。不过它的二级索引secondary index非主键索引中必须包含主键列,因此若是主键列很大的话,其余的全部索引都会很大。所以,若表上的索引较多的话,主键应当尽量的小。另外InnoDB的存储格式是平台独立。

InnoDB作了不少优化,好比:磁盘读取数据方式采用的可预测性预读、自动在内存中建立hash索引以加速读操做的自适应哈希索引(adaptive hash index),以及可以加速插入操做的插入缓冲区(insert buffer)等。

InnoDB经过一些机制和工具支持真正的热备份,MySQL的其余存储引擎不支持热备份,要获取一致性视图须要中止对全部表的写入,而在读写混合场景中,中止写入可能也意味着中止读取。

MyISAM存储引擎的特色和应用场景?

MyISAM是MySQL 5.1及以前的版本的默认的存储引擎。MyISAM提供了大量的特性,包括全文索引、压缩、空间函数(GIS)等,但MyISAM不「支持事务和行级锁」,对于只读数据,或者表比较小、能够容忍修复操做,依然可使用它。

特性

MyISAM「不支持行级锁而是对整张表加锁」。读取时会对须要读到的全部表加共享锁,写入时则对表加排它锁。但在表有读取操做的同时,也能够往表中插入新的记录,这被称为并发插入。

MyISAM表能够手工或者自动执行检查和修复操做。可是和事务恢复以及崩溃恢复不一样,可能致使一些「数据丢失」,并且修复操做是很是慢的。

对于MyISAM表,即便是BLOBTEXT等长字段,也能够基于其前500个字符建立索引,MyISAM也支持「全文索引」,这是一种基于分词建立的索引,能够支持复杂的查询。

若是指定了DELAY_KEY_WRITE选项,在每次修改执行完成时,不会当即将修改的索引数据写入磁盘,而是会写到内存中的键缓冲区,只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入磁盘。这种方式能够极大的提高写入性能,可是在数据库或者主机崩溃时会形成「索引损坏」,须要执行修复操做。

InnoDB与MyISAM对比

说了这么多估计看一眼也没记住,给你一张表,简单罗列两种引擎的主要区别,以下图。
引擎对比

其余存储引擎

MySQL还支持其余一些存储引擎,好比memory引擎、NDB集群引擎、CSV引擎,因为这些引擎没有上述InnoDB 和MyISAM 经常使用,这里不做介绍,感兴趣能够去翻MySQL文档了解。这里一样给出官方连接:https://dev.mysql.com/doc/refman/5.7/en/storage-engines.html
引擎列表

再说两句

这一篇是MySQL基础篇,我力求用通俗易懂和图表结合的形式给你们梳理这块知识,越是基础和底层的知识越容易被考察掌握程度,以上知识点均可能成为面试中的一个考察点,相信看完对MySQL事务和存储引擎应该有一个比较完整的理解。

最后,感谢各位的阅读,文章的目的是分享对知识的理解,若文中出现明显纰漏也欢迎指出,咱们一块儿在探讨中学习。

References

https://book.douban.com/subject/23008813/

https://juejin.im/post/5c519bb8f265da617831cfff#comment

https://tech.meituan.com/2014/08/20/innodb-lock.html

https://blog.csdn.net/shellching/article/details/8106156

https://coolshell.cn/articles/6790.html

https://zhuanlan.zhihu.com/p/29166694

https://dev.mysql.com/doc/refman/5.7/en/storage-engines.html

https://www.zhihu.com/question/27876575

https://www.runoob.com/mysql/mysql-transaction.html

https://blog.csdn.net/qq_35642036/article/details/82820178?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

https://github.com/CyC2018/CS-Notes/blob/master/notes/MySQL.md#b-tree-%E5%8E%9F%E7%90%86


更多

更多精彩原创关注公众号「后端技术学堂」大厂程序员,十年多编程学习经验,用通俗易懂的方式与你分享技术学习和程序员的那些事。
在公众号回复「资源」各类你想要都在里面。

精彩文章推荐:

我用大数据分析了一线城市1000多份岗位招聘需求,告诉你如何科学找工做
很是详细的 Linux C/C++ 学习路线总结!已拿腾讯offer
腾讯后台开发面试笔试C++知识点参考笔记
还能这么玩?我用VsCode画类图、流程图、时序图、状态图不要太爽!
面试官:你会几种redis分布式锁?我会三种!
最详细的我的博客教程搭建教程GithubPages+Jekyll 简约风格博客