Innodb中的事务和锁以及MVCC

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zx64881926/article/details/75150421

蚂蚁金服面试,主要问了一些jvm和mysql的知识,有些问题回答的模棱两可,再次总结一下。mysql因为其插件式存储引擎以及其较小的体积成为了许多应用中数据库的首选,Innodb引擎支持事务,外键并且支持行锁,被广泛的应用于OLTP业务中。

1.mysql的体系架构
mysql体系
上图是mysql的总体架构,可以看到插件式的存储引擎只是mysql的一个组件而已,引擎是基于表的,而并非是基于数据库的。
有一个问题:qcache和Innodb buffer pool有什么区别?
这个问题的本质还是存储引擎是基于表的,而不是基于数据库的这句话,innodb buffer pool是基于表的,存储的是表的数据,当查询数据时,会首先从内存中进行查询,如果内存中存在,数据将直接从内存中返回,从而提高查询的响应时间;而qcache是基于数据库的,缓存的是sql语句及其对应的结果集,qcache会跟踪系统中的每张表,若表发生变化,则和张表相关的所有查询缓存全部失效,且任何包含不确定结果的查询(如now())均不会被缓存。当检查到qcache有效的时候,mysql不会对sql语句做解析,优化等任何的处理,直接将结果集返回。

2.Innodb和MyISAM的区别
这两个引擎可谓是mysql中最常见的两个引擎,前者适用于OLTP业务中,而后者适用于OLAP业务中。下面给出一张表来对比两者区别
innodb vs myisam
关于聚集索引有一问题:
Innodb中聚集索引和非聚集索引的区别?
Innodb存储引擎表示索引组织表。即表中数据行顺序按照主键顺序存放(逻辑上均连续,物理上可能不一定连续,视具体情况,因为维护成本太高),而聚集索引就是每张表主键构成的一棵B+树。同时叶子节点存放的即为整张表的行记录数据的指针。由于实际的数据页只能按照一棵B+树进行排序所以一张表也只能拥有一个聚集索引,用主键进行范围查询是极快的,因为由双向链表进行逻辑上的链接。下图便是一个实际的聚集索引示例:
cluster index
非聚集索引的数据结构仍然是B+树,叶子节点不包含数据行的数据。叶子节点除了包含键值外,还包含相应数据行的聚集索引键,同样的查找 势必要多进行一倍的IO操作,下图是一个非聚集索引的示意图:
secondary index
另外提一下,MyISAM中采用堆表的表类型,行数据的存储按照插入的顺序存放。自然也谈不上什么聚集索引,以行标识符来标识数据行。
除此之外还有一个问题:
为什么要采用B+树做索引,而不采用B树做索引:
我认为有2点原因:
1).B树虽然非叶子节点中也含有数据,有可能在查询的时候只需走比B+树要少的层即可查找到数据。但是对于大多数节点(位于叶子的),B树由于每个节点都存放了聚集索引键/数据行的指针,导致B树节点大小较B+树要大,所以占用更多空间,导致更多的磁盘IO
2).更重要的一点,在B树中,如果想遍历一个范围或者说遍历所有数据,需要进行中序遍历,但是在B+树中,可以通过双向链表来遍历所有叶子节点。

3.事务的ACID特性以及mysql中如何保证这4个特性
这是一个特别好的问题,也是这篇blog的中点,直接把事务的特性和mysql的锁和MVCC一起很深入的考察了一下,PS:我发现蚂蚁金服的人面试,一不提前约时间,二不问具体问题,就问一个方面,让你谈谈对这方面的理解,然后你说到哪他感兴趣了就深入的问问。
3.1 事务ACID特性的理解
A(Atomic):原子性是指数据库的事务是一个不可分割的工作单位,只有数据库事务都成功才算成功,任何一个SQL的失败,数据库状态都必须回退到事务开始前的状态
C(Consistence):一致性是指事务将数据库的状态从一种状态转变为下一个一致的状态。在事务的开始和结束后,数据库的完整性约束都没有被破坏。
I(Isolation):隔离性是指事务之间对数据对象的读写是相互隔离的,具体是提交后可见还是提交后也不可见取决于隔离等级,前面两种情况分别为提交读(RC)和可重复读(RR)。
D(持久性):持久性是指事务一旦提交,其修改是永久性的,即使还未写入磁盘时发生宕机,也能恢复数据。
3.2 多版本并发控制(MVCC)
在innodb中“MVCC多版本一致性读”功能的实现是基于undo-log的。主要是为Repeatable-Read事务隔离级别做的。
innodb存储的最基本row中包含一些额外的存储信息,如下图所示:
ROW_REC
DATA_TRX_ID:最新修改此行记录的事务ID
DATA_ROLL_PTR:指向本数据行undo log,之前版本的数据就存于这里
DELETE BIT:标识此记录是否被删除
DB_ROW_ID:若指定了主键,则主键生成聚集索引,若未指定,以该列自动生成聚集索引。
当执行一个update语句时过程如下:
用排它锁锁定改行–>修改该行–>写redo log–>写undo log–>更新DATA_TRX_ID以及更新DATA_ROLL_PTR指向undo log中修改前的行。
当使用MVCC SELECT数据时(主要用于RR隔离):
1.如果行未被删除,DELETE BIT=0,则只查找事务ID版本小于该事务ID的记录
2.如果行被删除,DELETE BIT=0,则版本号必须是未定义的或者大于当前事务的版本号,确定了当前事务开始之前,行没有被删除。
MVCC详解
MVCC读的执行过程
在RC和RR隔离级别下,Innodb都会采用非锁定的一致性读,在RC下,对于快照数据,非一致性读总是读取非锁定行的最新一份快照数据,而在RR下,会去读取事务开始时的快照数据。
3.3 锁
Innodb中基本锁有以下4种:
行级锁
1). 共享锁(S Lock) : 允许事务读一行数据
2). 排它锁(X Lock) : 允许事务删除或更新一行数据
表级锁
3). 意向共享锁(IS Lock):事务想要获得一张表中某几行的共享锁
4). 意向排它锁(IX Lock):事务想要获得一张表中某几行的排它锁
由于Innodb引擎支持的均为行锁,所以意向锁其实不会阻塞除全表扫描之外的任何请求
Innodb中行锁有三种基本的算法:
1). record lock : 单个行记录上的锁
2). gap lock:锁定一个范围,但不包含记录本身
3). next-key lock : record lock + gap lock锁定一个范围,并且锁定记录本身。避免幻读
锁问题:
1). 脏读:所谓脏数据就是指那些尚未提交的非一致的数据,和脏页完全不同,脏页由于内存和磁盘不同步造成,最终终会达到一致。仅有RU下会出现脏读。
2). 不可重复读/幻读:innodb采用next-keys锁机制,不仅锁住行记录还会锁住范围,避免不可重复读和幻读
3). 丢失更新:数据库层面上可以避免,但应用程序中可能由于网络延迟等原因,一定要注意。
其实在innodb中,RC和RR都采用的是非锁定的一致性读,也不会因为锁而阻塞。
3.4 Innodb中如何实现ACID
隔离性:锁和MVCC
其他:redo undo
(待补充)

展开阅读全文

没有更多推荐了,返回首页