mysql8学习笔记28--InnoDB内核1
InnoDB存储引擎介绍
MySQL从5.5版本开始将InnoDB作为默认存储引擎,该存储引擎是第一个完整支持事务ACID特性的存储引擎,且支持数据行锁,多版本并发控制(MVCC),外键,以及一致性非锁定读。作为默认存储引擎,也就意味着默认创建的表都会使用此存储引擎,除非使用ENGINE=参数指定创建其他存储引擎的表。
InnoDB的关键属性包括:
• ACID事务特性支持,包括commit,rollback以及crash恢复的能力
• 行级别锁以及多版本并发控制MVCC
• 利用主键的聚簇索引(clustered index)在底层存储数据,以提升对主键查询的IO性能
• 支持外键功能,管理数据的完整性
ACID模型是关系型数据库普遍支持的事务模型,用来保证数据的一致性,其中的ACID分别代表:
• A:atomicity原子性:事务是一个不可再分割的工作单位,事务中的操作要么都发生,要么都不发生
• C:consistency一致性:事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。这是说数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性
• I:isolation独立性:多个事务并发访问时,事务之间是隔离的,一个事务不应该影响其它事务运行效果
• D:durability持续性:在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚
举例来说,比如银行的汇款1000元的操作,简单可以拆分成A账户的余额-1000,B账户的余额+1000,还要分别在A和B的账户流水上记录余额变更日志,这四个操作必须放在一个事务中完成,否则丢失其中的任何一条记录对整个系统来说都是不完整的。对上述例子来说,原子性体现在要么四条操作每个都成功,意味着汇款成功,要么其中某一个操作失败,则整个事务中的四条操作都回滚,汇款失败;
一致性表示当汇款结束时,A账户和B账户里的余额变化和操作日志记录是可以对应起来的;
独立性表示当汇款操作过程中如果有C账户也在往B账户里汇款的话,两个事务相互不影响,即A->B有四个独立操作,C->B有四个独立操作;
持久性表示当汇款成功时,A和B的余额就变更了,不管是数据库重启还是什么原因,该数据已经写入到磁盘中作为永久存储,不会再变化,除非有新的事务
其中事务的隔离性是通过MySQL锁机制实现
原子性,一致性,持久性则通过MySQL的redo和undo日志记录来完成
mysql> show variables like '%autocommit%'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | ON | +---------------+-------+ 1 row in set (0.00 sec) mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> select * from animals; +----+---------+ | id | name | +----+---------+ | 1 | dog | | 2 | cat | | 3 | penguin | | 4 | lax | | 5 | whale | | 6 | ostrich | +----+---------+ 6 rows in set (0.05 sec) mysql> update animals set name='dog2' where id=1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from animals; +----+---------+ | id | name | +----+---------+ | 1 | dog2 | | 2 | cat | | 3 | penguin | | 4 | lax | | 5 | whale | | 6 | ostrich | +----+---------+ 6 rows in set (0.00 sec) mysql> rollback; Query OK, 0 rows affected (0.02 sec) mysql> select * from animals; +----+---------+ | id | name | +----+---------+ | 1 | dog | | 2 | cat | | 3 | penguin | | 4 | lax | | 5 | whale | | 6 | ostrich | +----+---------+ 6 rows in set (0.00 sec) mysql>
为保证并发操作和回滚操作,InnoDB会将修改前的数据存放在回滚段中。InnoDB会在数据库的每一行上额外增加三个字段以实现多版本控制,第一个字段是DB_TRX_ID用来存放针对该行最后一次执行insert、update操作的事务ID,而delete操作也会被认为是update,只是会有额外的一位来代表事务为删除操作;第二个字段是DB_ROLL_PTR指针指向回滚段里对应的undo日志记录;第三个字段是DB_ROW_ID代表每一行的行ID。回滚段中的undo日志记录只有在事务commit提交之后才会被丢弃,为避免回滚段越来越大,要注意及时执行commit命令
InnoDB多版本控制
初始数据行的情况,六个字段的值分别是1,2,3,4,5,6
事务1修改该数据行,将六个字段的值分别*10,并生成回滚日志记录
事务2读取该数据行
事务2按照自己的事务ID和行数据中的事务ID做对比,并按照事务隔离级别选取事务1
修改前的回滚段中的数据返回
InnoDB和ACID模型
session1 mysql> start transaction; Query OK, 0 rows affected (0.00 sec) session2 mysql> start transaction; Query OK, 0 rows affected (0.00 sec) session1 mysql> select * from animals; +----+---------+ | id | name | +----+---------+ | 1 | dog | | 2 | cat | | 3 | penguin | | 4 | lax | | 5 | whale | | 6 | ostrich | +----+---------+ 6 rows in set (0.00 sec) session2 mysql> select * from animals; +----+---------+ | id | name | +----+---------+ | 1 | dog | | 2 | cat | | 3 | penguin | | 4 | lax | | 5 | whale | | 6 | ostrich | +----+---------+ 6 rows in set (0.00 sec) session1 mysql> update animals set name='cat2' where id=2; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 session2 mysql> select * from animals;###session1锁数据未释放,session2也能访问相同数据 +----+---------+ | id | name | +----+---------+ | 1 | dog | | 2 | cat | | 3 | penguin | | 4 | lax | | 5 | whale | | 6 | ostrich | +----+---------+ 6 rows in set (0.00 sec) session1 mysql> commit; Query OK, 0 rows affected (0.03 sec) session2 mysql> select * from animals;###session1锁释放,但session2访问到的数据依然是之前的数据 +----+---------+ | id | name | +----+---------+ | 1 | dog | | 2 | cat | | 3 | penguin | | 4 | lax | | 5 | whale | | 6 | ostrich | +----+---------+ 6 rows in set (0.00 sec) session2 mysql> commit; Query OK, 0 rows affected (0.00 sec) session2 mysql> select * from animals;###session2提交之后,再访问到的数据是修改后的数据 +----+---------+ | id | name | +----+---------+ | 1 | dog | | 2 | cat2 | | 3 | penguin | | 4 | lax | | 5 | whale | | 6 | ostrich | +----+---------+ 6 rows in set (0.00 sec) mysql>