MySQL事务原理

  • Post author:
  • Post category:mysql



实际上,我们研究事务的原理,就是研究


MySQL





InnoDB


引擎是如何保证事务的四大特性的。


而对于这四大特性,实际上分为两个部分。 其中的

原子性、一致性、持久性

,实际上是由


InnoDB


中的两份日志来保证的,一份是

redo log




日志

,一份是



undo log




日志

。 而

隔离性

是通过

数据库的锁

, 加上

MVCC



来保证的。


一、

redo log



重做日志,记录的是事务提交时数据页的物理修改,是用来实现事务的持久性。


该日志文件由两部分组成:

重做日志缓冲(




redo log buffer






以及

重做日志文件(




redo log file)



,


前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都存到该日志文件中


,


用于在刷新脏页到磁盘,


发生错误时


,


进行数据恢复使用。



如果没有


redolog


,可能会存在什么问题的?


我们知道,在InnoDB


引擎中的内存结构中,主要的内存区域就是

缓冲池

,在缓冲池中缓存了很多的

数据页

。 当我们在一个事务中,执行多个增删改的操作时,InnoDB


引擎会先操作缓冲池中的数据,如果缓冲区没有对应的数据,会通过后台线程将磁盘中的数据加载出来,存放在缓冲区中,然后将缓冲池中的数据修改,修改后的数据页我们称为

脏页

。 而脏页则会在一定的时机,通过后台线程刷新到磁盘中,从而保证缓冲区与磁盘的数据一致。 而缓冲区的脏页数据并不是实时刷新的,而是一段时间之后将缓冲区的数据刷新到磁盘中,假如刷新到磁盘的过程出错了,而提示给用户事务提交成功,而数据却没有持久化下来,这就出现问题了,没有保证事务的持久性。



那么,如何解决上述的问题呢?


有了redo log


之后,当对缓冲区的数据进行增删改之后,会首先将操作的数据页的变化,记录在


redo log buffer中。在事务提交时,会将


redo log buffer


中的数据刷新到


redo log


磁盘文件中。过一段时间之后,如果刷新缓冲区的脏页到磁盘时,发生错误,此时就可以借助于redo log


进行数据恢复,这样就保证了事务的持久性。 而如果脏页成功刷新到磁盘或者涉及到的数据已经落盘,此 时redolog


就没有作用了,就可以删除了,所以存在的两个


redolog


文件是循环写的。



那为什么每一次提交事务,要刷新


redo log


到磁盘中呢,而不是直接将


buffer pool


中的脏页刷新到磁盘呢 ?


因为在业务操作中,我们操作数据一般都是随机读写磁盘的,而不是顺序读写磁盘。 而redo log


在 往磁盘文件中写入数据,由于是日志文件,所以都是顺序写的。顺序写的效率,要远大于随机写。 这种先写日志的方式,称之为 WAL(


Write-Ahead Logging


)。

二、undo log


回滚日志,用于记录数据被修改前的信息


,


作用包含两个


:



提供回滚



(


保证事务的原子性


)




MVCC

(多版本并发控制


)




undo log





redo log


记录物理日志不一样,它是

逻辑日志

。可以认为当


delete


一条记录时,


undo log中会记录一条对应的


insert


记录,反之亦然,当


update


一条记录时,它记录一条对应相反的update记录。当执行


rollback


时,就可以从


undo log


中的逻辑记录读取到相应的内容并进行回滚。



Undo log




销毁




undo log


在事务执行时产生,事务提交时,并不会立即删除


undo log


,因为这些日志可能还用于MVCC





Undo log




存储




undo log


采用段的方式进行管理和记录,存放在


rollback segment回滚段中,内部包含1024





undo log segment



三、MVCC

1. 基本概念

(1)当前读


读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:

select … lock in share mode(




共享锁


)







select … for update、


update





insert





delete(


排他锁


)



都是一种当前读。


(2)快照读


简单的


select


(不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据, 不加锁,是非阻塞读。



  • Read Committed



    :每次


    select


    ,都生成一个快照读。


  • Repeatable Read



    :开启事务后第一个


    select


    语句才是快照读的地方。


  • Serializable



    :快照读会退化为当前读。

(3)MVCC


全称


Multi-Version Concurrency Control


,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL


实现


MVCC


提供了一个非阻塞读功能。


MVCC


的具体实现,还需要依赖于数据库记录中的

三个隐式字段



undo log




日志





readView




2. 实现原理

(1)隐藏字段


实际上除了自己创建的字段以外,InnoDB


还会自动的给我们添加三个隐藏字段及其含义分别是:


隐藏字段

含义

DB_TRX_ID

最近修改事务


ID


,记录插入这条记录或最后一次修改该记录的事务


ID




DB_ROLL_PTR

回滚指针,指向这条记录的上一个版本,用于配合


undo log


,指向上一个版本。

DB_ROW_ID

隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段。


而上述的前两个字段是肯定会添加的, 是否添加最后一个字段


DB_ROW_ID


,得看当前表有没有主键,如果有主键,则不会添加该隐藏字段

(2)undo log



回滚日志

,在


insert





update





delete


的时候产生的便于数据回滚的日志。






insert



的时候,产生的


undo log


日志只在回滚时需要,在事务提交后,可被立即删除。






update





delete



的时候,产生的


undo log


日志不仅在回滚时需要,在快照读时也需要,不会立即被删除。


① undo log版本链


不同事务或相同事务对同一条记录进行修改,会导致该记录的undo log生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。

(3)ReadView


ReadView


(读视图)是 快照读


SQL


执行时


MVCC


提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id


ReadView


中包含了四个

核心字段



字段

含义

m_ids

当前活跃的事务


ID


集合

min_trx_id

最小活跃事务


ID

max_trx_id

预分配事务


ID


,当前最大事务


ID+1


(因为事务


ID


是自增的)

creator_trx_id

ReadView


创建者的事务


ID


而在


readview


中就规定了版本链数据的

访问规则




trx_id



代表当前


undolog


版本链对应事务


ID




条件

是否可以访问

说明

trx_id ==creator_trx_id

可以访问该版本

成立,说明数据是当前这个事务更改的。

trx_id < min_trx_id

可以访问该版本

成立,说明数据已经提交了。

trx_id > max_trx_id

不可以访问该版本

成立,说明该事务是在ReadView生成后才开启。

min_trx_id <= trx_id<= max_trx_id

如果


trx_id


不在


m_ids


中,是可以访问该版本的

成立,说明数据已经提交。



不同的隔离级别,生成


ReadView


的时机不同:



  • READ COMMITTED



    :在事务中每一次执行快照读时生成


    ReadView





  • REPEATABLE READ



    :仅在事务中第一次执行快照读时生成


    ReadView


    ,后续复用该


    ReadView


所以呢,


MVCC


的实现原理就是通过


InnoDB


表的隐藏字段、


UndoLog


版本链、


ReadView


来实现的。而MVCC +


锁,则实现了事务的

隔离性

。 而

一致性

则是由


redolog





undolog


保证。



版权声明:本文为weixin_42318705原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。