1.名词解释
Atomicity(原子性)——事务要么全部完成,要么全部不完成。
实现方式:利用 undo log
但事务执行出错或者用户 rollback,系统通过undo log回滚到事务开始前的状态。
Consistency(一致性)——事务开始前与结束后,数据的完整性不会被破坏。
实现方式:利用回滚、恢复、以及并发时的隔离性,实现一致性
Isolation(隔离性)——事务的修改在提交前,其他事务对它是不可见的,即事务之间不相互影响。
实现方式:利用锁机制和MVCC来隔离事务
Durability(持久性)——事务提交后,对数据修改的结果会准确存储在数据库中,是永久的。
实现方式:利用 redo log
在 redo log 持久化后,系统崩溃,可以通过 redo log 恢复数据。
redo log——重做日志,记录数据页发生的变化。
redo log buffer ——redo的内存区域。
ibd——(磁盘)存储数据行和索引。
(data)buffer pool——数据和索引的缓冲区。
LSN——日志序列号。每次mysql数据库启动,都会比较磁盘数据页和redo log的LSN,二者一致才能正常启动。
持久化——内存数据写入磁盘的动作。
WAL——日志优先写的持久化方式。
脏页——内存中修改,但还没有写入磁盘的内存页。
CKPT——检查点,将脏页刷写到磁盘的动作。
TXID——每个事务对应的编号。
2.CSR前滚动作
以下图为例,上方大矩形为内存,下方大矩形为磁盘区。
内存区的三个矩形从左到右依次是,“undo buffer”—“data buffer pool”—“redo buffer”
磁盘区的三个矩形从左到右依次是,“undo log”—“数据页ibd文件”—“redo log”
在事务开始前,磁盘数据页(红色圆形)有一行数据“a=1"。
1)begin 磁盘数据页的LSN=01
2)将磁盘数据页”a=1"调用到内存中,此时data buffer pool的LSN=01
3)修改数据,变成"a=2",此时data buffer pool的LSN=02。
4)在redo buffer中,会把a=1修改成a=2的变化写入redo日志中,并且LSN=02
5)将redo buffer中的redo log刷写到磁盘中,此时commit才算真正的成功,并且redo log会被打上commit的标记。
!!!!!!!!!然后断电了!!!!!!!!!
6)重新启动数据库,磁盘数据页的LSN=01与redo log(磁盘)的LSN=02不一致,判断出redo log中的数据没有写入到磁盘。此时会将二者都加载至内存,重新构造脏页。
7)触发CKPT,将脏页内容写入磁盘中,并且LSN=02,与磁盘的redo log的LSN=02保持一致。
8)Mysql正常启动。
ps.
当执行commit后,redo log会被刷写到磁盘;
同一时间进行的,还未提交的,在redo buffer的事务也会被刷写到磁盘中。
3.undo回滚
说明图片与2的图一样。
在事务开始前,磁盘数据页(红色圆形)有一行数据“a=1"。
修改操作前的事务是TXID=t0
begin开始后,TXID=t1
情况一:一切顺利,undo用不到。
1)begin 磁盘数据页的LSN=01 TXID=t1
2)将磁盘数据页”a=1"调用到内存中,此时data buffer pool的LSN=01,同时undo log中也记录a=1 TXID=t1(修改前状态)。
3)然后就是前滚操作(同上),在redo buffer和磁盘redo log中也有TXID=t1的记录,commit执行成功,数据写入磁盘。
4)undo log中被标记commit,使命完成。
情况二:修改数据后,rollback
1)在修改数据a=2后,执行rollback操作。
2)会将磁盘的undo log加载到内存中,在undo buffer中,将已更改的a=2数据修改回a=1。
3)内存中实现了回滚操作,最终a=1。
情况三:提交前,断电
1)redo buffer中,a=2 LSN=02写入到redo log中,但还没有把redo log写入磁盘中。
2)断电
3)启动Mysql
磁盘中的redo log 的LSN=01 TXID=t0
ibd数据文件的LSN=01 TXID=t1
磁盘undo log的TXID=t1
LSN相同,但undo log的TXID不同,说明事务没有提交,buffer中的数据丢失,并丢弃undo log。
4)不用前滚和回滚,a=1。
情况四:未提交,但被其他事务顺带写入磁盘
1)修改的数据已经写入redo buffer中的redo log中,redo log还没有刷写到磁盘中,也没有主动commit该事务。
2)此时,redo log中的内容被其他事务顺带写入磁盘,包括:
LSN=02 TXID=t1 数据a=1变成a=2的过程 以及本事务未提交的标记。
3)又双叒叕断电了…
4)启动mysql,对比磁盘数据页LSN=01和磁盘redo log的LSN=02,出现不一致
5)将二者加载到内存中,构造脏页,重新变成断电前的状态,a=1变成a=2的过程,进行前滚。
6)由于磁盘redo log中TXID=t1被标记未提交,于是在data buffer中找到对应的TXID=t1事务,将undo log中的数据加载到内存中,进行回滚操作,data buffer中a=1,保证所有LSN=01。