MySQL事务机制

基础概念

事务是访问和更新数据的基本单元,事务保证一批数据要么全部执行要么都不执行。
MySQL只有使用了InnoDB引擎创建数据库和表才支持事务。
事务用来管理CRUD操作。

事务的四大特性

事务的四大特性是指事务的ACID特性:原子性(Automatic)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。

  • 原子性:是指事务要么全做要么都不做,如果在中间发生错误就会执行回滚操作,撤销之前的操作。
  • 一致性:是指事务执行结束后,数据库的完整性没有被破坏,执行前和执行后数据都是合法的状态。完整性包括但不限于:实体完整性、列完整性、外键约束、用户自定义完整性。
  • 隔离性:数据库允许多个事务同时对数据进行读取和修改,隔离性保证多个事务并发执行的时候数据的合法性不被破坏。数据的隔离级别分为四个:读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复的(Repeatable Read)、可串行化(Serializable)
  • 持久性:是指事务结束后对数据的修改是永久的,即使系统故障也不会丢失。

事务的基本操作(提交、回滚)

开启事务:begin transaction
提交事务:commit
回滚事务:rowback

事务的隔离级别

事务的隔离性专注于不同事务之间的影响。当多个事务同时执行的时候,要保证不同事务之间不能相互影响,这是标准的隔离性性体现(可串行化)。但是在实际中,我们对响应速度的需求使隔离级别往往达不到这样,通常使用的读已提交和可重复度。
事务并发引起的问题

  • 脏读:事务A读取到事务B未提交的数据(脏数据)。
  • 不可重复读:事务A先后两次读取的数据不一致。脏读是指读到没有提交的数据,而不可重复读是读到已提交的数据。
  • 幻读:事务A先后两次查询数据,结构两次查询的数据条数不一样。不可重复读侧重于数据的修改,而幻读侧重于数据的插入和删除。
    对于这三种事务并发问题MySQL共有四种隔离级别相与之对应。
    在这里插入图片描述
    可以看到读未提交对三种并发问题都不能有效杜绝,因而开发中比较少用;可串行化可以防止所有的问题,但是它的开销很大,因而开发中也很少用。

日志与事务

MySQL中有三种日志:Redo log、Undo log和bin log。

Redo log

是重做日志,用来实现事务的持久性。
MySQL的数据都是存放在磁盘上的,但是如果每次都从磁盘上读取数据,那么效率无疑会大大降低。所以MySQL使用一个Buffer Pool,用来存放每次从磁盘读取到的数据。当一次请求到达时,MySQL首先会查找Buffer Pool,如果没有找到相应的数据,就从磁盘中读取,然后存放到Buffer Pool中。Buffer Pool会定期将数据写回到磁盘中,称为刷脏。
如果服务器突然断电,那么Buffer Pool中的数据就会丢失,针对此类情况,MySQL使用Redo log解决。当数据被修改时,除了要修改数据,还要在Redo log中记录这个操作的结果。当MySQL重启的时候可以直接从中读取数据。
Redo log采用WAL模式(writer-ahead-logging),即MySQL现在Redo log记录此次操作,然后再执行该操作。这样就保证了数据不会丢失。

  • 刷脏是随机I/O,而Redo log是采用追加的方式。
  • 刷脏是以数据页(Page)为单位的,MySQL默认页大小是16KB,一个Page上一个小修改都要整页写入;而redo log中只包含真正需要写入的部分,无效IO大大减少。

binlog

  • binlog是MySQL系统自带的日志系统,是二进制日志。而Redo log是InnoDB引擎实现的。
  • Redo log是为了保证MySQL宕机也会影响持久性,binlog保证服务器可以基于时间点回复数据。
  • binlog在事务提交时写入,而Redo log的写入时机比较多元。

Undo log
是回滚日志。是实现事务原子性的重要原因,当事务失败或者回滚时,它能撤销该事务成功执行的所有操作。
它与Redolog正好相反,它记录的是事务的逻辑操作。当事务回滚时MySQL根据Undo log记录的操作做相反的操作,从而撤销之前的所有操作,还原数据。

在事务结束后并不会立刻删除undo log,还会检查mvcc是否用到了这个日志。

MVCC

导读概念

当前读:读取的记录的最新版本,读取的时候要保证当前记录不会被其他记录修改,所以需要对读取的记录加锁。
select … for update, select … in lock share mode, insert, update, delete
如果读取的记录被其他事务加锁(独占锁),则当前读会阻塞,直到其他事务释放锁。

快照读:普通的select 语句,不加锁(非阻塞),读取的就是记录的快照,有可能是最新数据,有可能是历史数据。
read commit : 每次select 都是一个快照读
repeatable read:在事务开启的第一个select读取的数据(并不是非要执行select语句才叫做第一个select,update/delete时都需要先读取数据。),才产生一个快照读
serializable:快照读变更为当前读,也就是所有的语句都会加锁。

MVCC叫做多版本并发控制,一般情况下,事务性储存引擎不是只使用表锁,行加锁的处理数据,而是结合了MVCC机制,以处理更多的并发问题。Mvcc处理高并发能力最强,但系统开销 比最大(较表锁、行级锁),这是最求高并发付出的代价。

InnoDB的 MVCC ,是通过在每行记录的后面保存两个隐藏的列来实现的。

DB_TRX_ID:记录插入或修改改记录的最后一次事务id
DB_ROLL_PTR:回滚指针,配合undo log,用于记录这条记录的上一个版本
ROW_ID:当这张表没有主键或者非空唯一字段,就会创建一个隐藏列,作为主键。

在这里插入图片描述

使用MySQL提供的工具idb2sdi,查看 ibd2sdi /var/lib/mysql/{database}/table.ibd
在这里插入图片描述
在这里插入图片描述

undo log
在insert的时候产生的undo log,只在事务回滚的时候需要,当事务提交时就可以删除了。
在update/delete操作产生的undo log,不仅在事务回滚是需要,在快照读的时候也需要。

undo log 版本链
当一个事务对一条记录进行修改,就会记录记录当前事务的修改id,同时产生一条undo log日志。当前记录的回滚指针指向改记录的undo log日志位置。
在这里插入图片描述

readview(读视图)
快照读sql执行时,mvcc读取事务的依据。在readview里面有几个重要字段

  • m_ids: 记录当前活跃的事务id集合
  • min_trx_id: 记录最小活跃事务id
  • max_trx_id: 预分配事务id(最大事务id+1)
  • creator_trx_id: 当前readview创建者的事务id

版本链规则访问规则
trx_id : 当前版本(undo log 日志)的事务id
有以下4条访问规则

  1. trx_id == creator_trx_id: 可以访问该版本,说明该版本是当前事务创建的
  2. trx_id < min_trx_id:可以访问该版本,说明该版本事务已经提交
  3. trx_id > max_trx_id:不能访问该版本,说明该版本是在readview开启之后才创建的。
  4. (min_trx_id <= trx_id <= max_trx_id) and (trx_id not in m_ids):可以访问,说明事务已经提交

注:只有在生成快照读的时候才会产生readview,所以readview要在不同的事务隔离级别下分析,不能一概而论。

第一个select查询
在这里插入图片描述
对于事务4的第一次select查询,此时只产生了1和2两个undo log日志,所以从trx_id=2开始比较。
发现trx_id=2的快照不满足任何条件,继续比较trx_id=1的快照,发现第二条满足。所以事务4读取到的就是trx_id=1的快照记录。

第二个select

在这里插入图片描述
对于第二次select,事务5查询时事务2已经提交,所以2从m_ids集合中剔除。
从版本链的id事务id中(4,3,2,1)依次代入4个条件,发现trx_id=2的快照满足。

第三次select

在这里插入图片描述

对于第三次select,事务5查询时事务3已经提交,所以3从m_ids集合中剔除。
从版本链的id事务id中(4,3,2,1)依次代入4个条件,发现trx_id=3的快照满足。

在RR隔离级别下,当第一次select时就生成了readview,所以在整个事务中读取的数据都是相同的,因此RR隔离级别可以预防不可重复读。

在这里插入图片描述

  • readview+undo log版本链+隐藏字段 实现了MySQL的mvcc特性
  • mvcc+锁 实现了事务的隔离性
  • redo log 记录了sql操作的记过,实现了事务的持久性
  • undo log 记录了sql的逻辑操作,实现了事务的原子性
  • 持久性+原子性 一起实现了事务的一致性。

参考博客一
参考博客二
参考三

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值