您的位置:首页 > 博客中心 > 数据库 >

细聊MySQL的Innodb存储引擎(一)

时间:2022-03-14 04:03

        从MySQL5.5开始,Innodb就成为MySQL的默认存储引擎了。可想而知,Innodb已经成为MySQL的主要生产方式。那Innodb到底有什么本事能够击败其它几位存储引擎而荣登宝座呢?下面,我就来和大家一起探讨探讨牛逼的Innodb引擎。Innodb涉及到的知识点比较多,所以我会分几篇来叙述,此篇主要介绍Innodb的基本概念和架构。


        要了解Innodb,首先需要了解MySQL的ACID模型。何为ACID?ACID指的是事务的原子性(A)、一致性(C)、隔离性(I)、持久性(D)。

        原子性表示事务是不可分割的。比如一个事务中包括一个插入操作和一个更新操作,那么这两个操作要么一起完成,要么一起撤销,不能某一个完成,另一个未完成。

        一致性指的是关系一致性(个人理解),比如A表与B表有外键约束的关系,A表的主键是B表的外键,那么当A表某一个记录被删除时,B表引用此记录的行也要被删除,从而保证数据一致。

        隔离性指某个事务内的操作对外界不可见,除非此事务被提交。比如同时有两个客户端对同一个表进行操作。A客户端首先读取了test表,查看到有一项记录t1=1,此时B客户端对test表进行更新操作,使t1=2,在B客户端进行更新操作后,A客户端再次读取test表,此时查看到的结果仍然是t1=1,这就表明B的操作对A是不可见的,这就叫做隔离性。

        持久性,这个很好理解,就是指数据操作后要保持它的状态,无论服务器重启、关机。


        Innodb是支持事务的存储引擎,为了使事务具有以上所描述的ACID特性。Innodb使出了浑身解数,运用了各种空间管理及锁管理技术,在保证运行效率的基础上实现了事务特性。下面,我们就来研究下Innodb到底是使用了哪些技术来实现这些特性的。

        Innodb的锁

        锁的作用是保证数据的一致性、隔离性与原子性。MySQL有行级锁与表级锁。行级锁可以对数据中的某一行加锁,当进程获取行级锁时,其它进程可对同一表中的其它行进行操作。而表级锁只能对整个表进行加锁。Innodb是实现行级锁的,当某一行被处理它的进程获取锁时,其它的进程就不能处理这一行了,而必须等待持有锁的进程释放锁后才能处理。这样,数据在某一时刻或某一事务中就只能被一个会话修改,从而保证数据的一致性。其原理和互斥资源的访问差不多。

        Innodb实现了标准的行级锁,行级锁有两种类型,一种为共享锁,另一种为独占锁。共享锁允许多个会话同时读某一行,独占锁则不允许,必须等待直到持有锁的会话释放锁后才能读取。而对于写操作,共享锁与独占锁都必须等待持有锁的会话释放锁后才能获取锁,进而进行操作。

        此外,MySQL为了支持更高粒度的锁机制,还设计了意向锁。意向锁是为正式加锁前做准备的。意向锁分为共享意向锁与独占意向锁。比如需要更新一条记录,那么,如果在执行更新记录前加上独占意向锁,那么在更新时会立即获得独占锁。设计意向锁的主要目的是向其它的会话展示当前会话正准备获取锁。意向锁为表级锁,并且它不会阻塞任何操作。下表主要展示行级锁与意向锁之间的兼容性。如果锁之间兼容,则事务可以同时获取,否则事务只能等待当前持有的锁释放才能获取。



XIXSIS
X冲突冲突冲突冲突
IX冲突兼容冲突兼容
S冲突冲突兼容兼容
IS冲突兼容兼容兼容


        X为独占锁

        IX为意向独占锁

        S为共享锁

        IS为意向共享锁


        锁之间的冲突可能会导致死锁,如果两个会话互相等待对方释放锁,而自身又没有主动释放锁时就会导致死锁。以下是一个死锁的例子:


        首先创建表并插入测试数据


idname1wangweiak472wangweim4a1



测试一中的观察点2的结果集为

idname
1wangweiak47
2wangweim4a1
3google


测试一中的观察点3的结果集为

idname
1wangweiak47
2wangweim4a1


        可知在A事务为提交的时候,B事务对A事务的插入操作是不可见的。


测试二中的观察点1的结果集为

idname
1wangweiak47
2wangweim4a1

测试二中的观察点2的结果集为

idname
1wangweiak47
2wangweim4a1
3google

测试二中的观察点3的结果集为

idname
1wangweiak47
2wangweim4a1

        可知在A事务提交后,如果B事务未提交,则B事务对A事务的插入操作仍然是不可见的。在REPEATABLE-READ隔离级别,事务以第一次的查询快照为准,别的事务不管提交与否,对本事务均是不可见的。


        2、以READ-COMMITTED模式启动服务器。注意,当设置READ-COMMITTED与READ-UNCOMMITTED隔离等级时,需设置参数binlog_format=row。

        执行测试用例可知,测试一中的结果与REPEATABLE-READ隔离级别的测试结果相同。在测试二中,结果如下:


测试二中的观察点1的结果集为

idname
1wangweiak47
2wangweim4a1

测试二中的观察点2的结果集为

idname
1wangweiak47
2wangweim4a1
3google

测试二中的观察点3的结果集为

idname
1wangweiak47
2wangweim4a1
3google


        在测试二中,当A事务提交后,B事务就能获取A事务最新插入的数据。如果B事务在A事务提交之前用相同的查询条件查询过结果集,那么B事务两次获取的结果集就会不一样,导致脏读。

        3、以READ-UNCOMMITTED模式启动服务器,按测试用例执行后可知,在测试一中,当A事务进行插入操作未提交时,B事务就能获取A事务插入的数据。所以,它的隔离性更差。


        4、SERIALIZABLE模式为最强的隔离等级,因为服务器是将事务串行化来逐个处理的,但这个模式下也会产生大量的超时现象和锁竞争。

本文出自 “” 博客,请务必保留此出处

热门排行

今日推荐

热门手游