最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

Mysql架构_事务原理与锁机制_MVCC日志

XAMPP相关 admin 731浏览 0评论

Mysql架构&事务原理与锁机制&MVCC日志(undo log redolog binlog)两阶段提交&组提交

想要进一线互联网大厂公式,MYSQL是绕不开的坎,对于MYSQL的事务隔离机制以及日志相关知识网上众说纷纭,你抄我我抄你,今天我要详细总结一下相关知识,形成完整体系,补充一句,下面所讲全是干货,废话就不多说了,直接讲解知识,欢迎留言评论,不足纠正!

下文主要针对MYSQL的innodb存储引擎。

01
mysql的架构

首先,我们从架构开始说起。mysql分为server层与存储引擎层,server层包含连接器、分析器、优化器、执行器。

接下来以一条sql查询语句执行过程介绍各个部分功能。

客户端执行一条sql:

1、首先由连接器进行身份验证,权限管理

2、若开启了缓存,会检查缓存是否有该sql对应结果(缓存存储形式key-vlaue,key是执行的sql,value是对应的值)若开启缓存又有该sql的映射,将结果直接返回;

4、分析器进行词法语法分析

5、优化器会生成执行计划、选择索引等操作,选取最优执行方

6、然后来到执行器,打开表调用存储引擎接口,逐行判断是否满足查询条件,满足放到结果集,最终返回给客户端;若用到索引,筛选行也会根据索引筛选。

02
mysql的事务原理与锁机制

基础知识:

事务:最小不可拆分单元,

事务特性:ACID

原子性:一些列操作要么全部成功,要么全部失败

隔离性:事务的结果只有提交了其他事务才可见

一致性:数据库总时从一个一致状态变到另一个一致状态

持久性:事务提交后,对数据修改永久的

事务的并发问题:

脏读:读到未提交的数据

不可重复读:一个事务下,两次读取数据不一致(侧重内容数据的修改)

幻读:一个事务下,两次读到数据总数不一致,读到了新插入的行(侧重记录行的插入删除)

2.1

隔离级别原理及解决问题分析

读未提交:直接读取数据,不能解决任何并发问题

读已提交:读操作不加锁,写操作加排他锁,解决了脏读,利用MVCC实现,每一句语句执行前都会生成Read View(一致性视图)

可重复读:MVCC实现,只有事务开始时会创建Read View,之后事务里的其他查询都用这个Read View。解决了脏读、不可重复读,快照读(普通查询,读取历史数据)使用MVCC解决了幻读,当前读(读取最新提交数据)通过间隙锁解决幻读(lock in share mode、for update、update、detete、insert),间隙锁在可重复读下才生效。(默认隔离级别)

可串行化:使用锁,读加共享锁,写加排他锁,串行执行

2.2

幻读问题详解

1、创建tx实验表

DROP TABLE IF EXISTS `tx`;
CREATE TABLE `tx` (
  `age` int(5) DEFAULT NULL,
  `name` varchar(5) DEFAULT NULL,
  `id` int(5) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of tx
-- ----------------------------
INSERT INTO `tx` VALUES ('20', '张三', '1');
INSERT INTO `tx` VALUES ('20', '李四', '2');
————————————————

2、

dre0085

结论(仔细理解,讲收获满满,本人认真总结的):

1、发现RR隔离界别若只快照读与当前读没有幻读问题,快照读(普通查询,如select * from table)读取旧的历史版本,用MVCC实现(MVCC原理下文分析),会在事务开始时生成一个Read View,之后都用这个Read View实现RR隔离级别。当前读(select … for update ,select … lock in share mode ,update/insert/delete语句)读取最新数据版本,依靠间隙锁或则临键锁解决幻读,当你事务T1执行当前读,然后事务T2插入语句,事务T2会被阻塞住,插不进去。

2、当你事务T1中先执行快照读,事务T2插入数据并提交,事务T1再执行当前读(比如以相同条件更新数据),会发现出现幻读,更新到了新插入行的数据(白话文解释:事务1先以某个条件比如age=20的查询得到2条数据,然后事务2插入新的数据age也为20然后提交事务,此时事务1更新age=20的数据,发现更新到了3行,把事务T2新插入的那行也更新了,所以幻读注重你插入新数据都修改改到了新插入的数据,而不可重复读是你修改了某个数据,两次查询得到不一致结果。)

2.4

MVCC实现原理

多版本并发控制。

原理提炼总结:使用版本链+Read View

详解:

版本链

同一行数据可能有多个版本

innodb数据表每行数据记录会有几个隐藏字段,row_id,事务ID,回滚指针。

1、Innodb采用主键索引(聚簇索引),会利用主键维护索引,若表没有主键,就用第一个非空唯一索引,若没有唯一索引,则用row_id这个隐藏字段作为主键索引。

2、事务开启会向系统申请一个事务ID,严格递增,会向行记录插入最近操作它的那个事务的ID

3、undolog会记录事务前老版本数据,然后行记录中回滚指针会指向老版本位置,如此形成一条版本链。因此可以利用undo log实现回滚,保证原子性,同时用于实现MVCC版本链。

dre00085

Read View

读已提交隔离级别下,会在每次查询都生成一个Read View,可重读读只在事务开始时生成一个Read View,以后每次查询都用这个Read View,以此实现不同隔离界别。

Read View里面包含些什么?

一个数组+up_limit_id(低水位)+low_limit_id(高水位)(这里的up,low没写错,就是这么定义的)

1、数组里包含当前活跃事务ID(未提交事务),低水位就是活跃事务最小ID,高水位就是下一次将分配的事务ID,也就是目前最大事务ID+1。

03
日志机制分析

前置知识,为了保证事务ACID中的一致性与原子性,mysql采用WAL,预写日志,先写日志,合适时再写磁盘。

3.1

undo log

回滚日志

undolog记录事务开始前老版本数据,用于实现回滚,保证原子性,实现MVCC,会将数据修改前的旧版本保存在undolog,然后行记录有个隐藏字段回滚指针指向老版本。

3.2

redo log

物理日志

作用:会记录事务开启后对数据做的修改

特性:空间一定,写完后会循环写,有两个指针write pos指向当前记录位置,checkpoint指向将擦除的位置,redolog相当于是个取货小车,货物太多时来不及一件一件入库太慢了这样,就先将货物放入小车,等到货物不多或则小车满了或则店里空闲时再将小车货物送到库房。用于crash-safe,数据库异常断电等情况可用redo log恢复。

写入流程:先写redo log buffer,然后wite到文件系统的page cache,此时并没有持久化,然后fsync持久化到磁盘

写入策略:

根据innodb_flush_log_at_trx_commit参数控制(我的记忆:innodb以事务的什么提交方式刷新日志)

0——>事务提交时只把redo log留在redo log buffer

1——>将redo log直接持久化到磁盘(所以有个双“1”配置,后面会讲)

2——>只是把redo log写到page cache

3.3

bin log

用于主备同步

有3种格式:

1、row:记录整行数据,更新记录更新前后的数据

缺点:记录每行数据,占空间

2、statement:记录整条sql语句

缺点:可能造成主从不一致

如:mysql> delete from t where a>=4 and b<=5 limit 1;

主库是索引a,那么删除a=4

备库是索引b,那么删除b=5

3、mixed:会判断statement格式下sql语句是否会造成主备不一致,不造成就statement格式,否则就row格式

写入机制:

1、事务执行过程中将日志记录到binlog cache(系统为binlog分配了一块内存,每个线程一份)

2、事务提交时,执行器把binlog cache里的完整事务写入到binlog中,并清空binlog cache

write:把日志写到文件系统的page cache,没有写磁盘,速度快

fsync:将数据持久化到磁盘的操作,这时才占磁盘IOPS

根据sync_binlog参数控制:

0——>只write,不fsync

1——>每次fsync

N>1——>每次事务都write,等累积到N后才fsync,可以将sync_binlog设置大一点提高性能(可以提高IO性能,但是若发生异常,日志会丢失)

这里sync_binlog和innodb_flush_log_at_trx_commit配和设置双1模式

04
两阶段提交

想要全面了解两阶段提交,我接下从这3个方面分析:

1、何为两阶段提交?

2、为什么要两阶段提交?

3、两阶段提交的过程是怎样的?

何为两阶段提交?(2PC)

mysql中在server层级别有个binlog日志,归档日志,用于备份,主从同步复制,如果采用一主多从架构,主备切换,那就必须用到binlog进行主从同步,此时事务提交就必须保证redolog与binlog的一致性,一般情况没有开启binlog日志,事务提交不会两阶段提交,若需要主从同步就必须开启binlog使用两阶段提交保证数据一致性。

为什么要两阶段提交?

保证redolog与binlog一致性,保证事务在多个引擎的原子性。

两阶段提交过程?

Prepare 阶段:InnoDB 将回滚段undolog设置为 prepare 状态;将 redolog 写文件并刷盘;

Commit 阶段:Binlog 写入文件;binlog 刷盘;InnoDB commit;

redolog与binlog怎样联系起来的?(XID)

崩溃恢复的时候,会按顺序扫描redo log,若redolog既有prepare又有commit,直接提交,如果碰到只有parepare、而没有commit的redo log,就拿着XID去binlog找对应的事务。

转载请注明:XAMPP中文组官网 » Mysql架构_事务原理与锁机制_MVCC日志

您必须 登录 才能发表评论!