mysql事务、日志、MVCC讲解

本文详细解析了MySQL的事务特性(ACID)、日志系统(包括undo log、redo log、binlog、relaylog)以及主从复制过程。还介绍了两阶段提交确保日志一致性,以及MVCC如何解决并发控制问题。通过案例分析,阐述了MVCC的可见性算法及幻读现象。同时,讨论了不同隔离级别对快照读的影响。
摘要由CSDN通过智能技术生成


本文讲解的是mysql的事务和日志之间的关联,并有部分MVCC的讲解。有和理解错的话请指正。

事务

事务的特性(ACID):
在这里插入图片描述

  • 原子性(A):在同一个事务中存在的n多条sql语句,要么全部成功,要么全部失败。如果有部分sql失败了,则所有sql结果通过undolog回滚日志来恢复初始状态
  • 一致性(C):事务执行之前和执行之后数据库均处于一致性状态。它是由 原子性、隔离性、持久性来实现的
  • 隔离性(I):多个事务操作同一张表的时候,每个事务互不干扰。锁、MVCC多版本并发控制来实现 数据安全问题用RR
  • 持久性(D):当事务被提交以后数据库中的数据就会被写入到磁盘中,数据改变就是永久性的了。通过redolog来实现

日志

在这里插入图片描述

日志类型:

  • undolog:回滚日志 原子性和MVCC的支撑
  • redolog:前滚日志 将数据持久化
  • binlog: 主从复制
  • relaylog:中继日志 在进行主从复制时 从机里先存储的日志
  • slowlog:慢查询日志 超过指定时长的sql语句
  • errorlog:错误日志

    undolog、redolog归属于Innodb 存储引擎
    binlog、relaylog、slowlog、errorlog归属于 mysqlserver

binlog、relaylog(主从复制)

在这里插入图片描述

  • 多线程进行操作master数据库,将数据存放到数据库中,并生成binlog记录,主从数据库要保证数据的同步一致性,主从直接会由IO Thread线程读取 master的binlog同步到slave内,并生成relaylog,然后由SQL Thread线程回放数据,保证主从两个数据库数据一致

redolog(两阶段提交)

  • redolog 是顺序读写机制,数据库数据属于随机读写机制,因为顺序读写效率远高于随机读写,所以操作数据库时,先将数据存到redolog中记录,然后再从redolog中放到数据库磁盘中(采用了WAL技术)。如果写到数据库的时候断电或宕机之类的,恢复后会从redolog中继续同步;如果写到redolog时出现断电或宕机则数据丢失。
    WAL:write ahead log 预写日志
两段提交

在这里插入图片描述

  • 为了保证redolog和binlog的数据同步一致性,则采用了两段提交的方式。
    数据想写入redolog中其状态为perpare状态(此状态的数据不能进行恢复),然后将数据写到binlog中,最后将redolog的数据提交。 如果再步骤1出现问题,在服务器恢复后检测到redolog有perpare状态的数据,则去binlog中找对应的数据,若未找到则删除redolog的此数据记录,在binlog中找到了,则将redolog中此数据commit;如果步骤2出现问题,先检测redolog记录,然后再去binlog中找对应的,找到commit,未找到删除。

MVCC (多版本并发控制)

MVCC 被称为多版本并发控制,它是为了提高数据库并发性能,以不加锁的方式来解决读写操作并发问题。
场景1
在这里插入图片描述
场景2
在这里插入图片描述

  • 当前读:读取当前的数据,即最新的数据(update、delete、insert、select…for update、select … lock in share mode可触发)
  • 快照读:读取历史数据(select 可触发)
mysql 存在的并发场景
  • 读读 不存在数据安全问题
  • 读写 脏读、幻读、不可重复读(MVCC解决的问题)
  • 写写 更新丢失
MVCC的组成
  • 隐藏字段 数据库的表在定义的时候除了我们自己声明的字段之外,还会有其他隐藏的字段

    • DB_TRX_ID 最近事务的id。创建这条记录或者最新更改这条数据的事务id
    • DB_ROLL_PRT 回滚指针,指向了记录上一个版本
    • DB_ROW_ID 隐藏主键,如果表没有主键,则会生成一个6字节的rowid
  • undolog 在进行 insert、delete、update操作时生成的方便回滚到历史数据的日志
    在这里插入图片描述
    因此undolog会形成一个链表,链首是最新的旧记录,链尾是最旧的旧记录,
    当undolog的日志记录达到一定值时,后台有一个purge线程进行删除操作

  • readview 读视图,在事务进行快照读的时候产生的读视图,保存的并不是实际的数据,而是事务的相关信息。

    • trx_list 当前系统活跃的事务id列表
    • up_limit_id 活跃列表中事务id最小的值
    • low_limit_id 系统尚未分配的下一个事务id
案例分析
  • 案例1图案:
    在这里插入图片描述
    readview视图字段对照
    在这里插入图片描述

  • 案例二图案:
    在这里插入图片描述
    readview视图字段对照
    在这里插入图片描述

经过两次案例结果发现,readview值是一样的,可见性算法也是一样的,但是最后的结果不一致,可以猜测案例二的蓝色的readview和橙色的readview是否是一样的?
在这里插入图片描述

根据可见性算法判断后发现和案例二的结果一致,因此可以确定猜测是对的。

因此可以得出一个结论:
第一次查询的时候生成了readview,第二次查询的时候沿用了第一次的readview

注意:由此可以关联到隔离级别
(RC:不可重复读 RR:幻读)
1、如果是RC(读后提交)隔离级别,那么每次进行快照读的时候都会产生新的readview
2、如果是RR(可重复读)隔离级别,那么只有在当前事务进行第一次快照读的时候产生readview,之后的都是沿用第一次的readview
可见性算法
	1、首先比较DB_TRX_ID < up_limit_id,如果小于,则当前事务能看到DB_TRX_ID所在的记录,如果大于等于进入下一个判断
	2、然后判断DB_TRX_ID >= low_limit_id,如果大于等于则表示DB_TRX_ID 所在的记录在readview生成后才出现,那么对于当前事务不可见,如果小于进去下一个判断
	3、然后判断DB_TRX_ID是否在活跃事务中,如果在 则表示在readview生成时刻,这个事务还在活跃状态,还没有commit,修改的数据当前事务也看不到;如果不在,则说明这个事务在readview生成之前就开始commit,那么修改的结果是可见的
幻读

其根本原因是:当前读和快照读一起使用,如果同一个事务中只有快照读则不会出现幻读问题。
MVCC解决不了幻读问题,幻读是加锁解决的
比如:select * from table for update;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值