MySQL中的事务

1.事务四大特性

原子性:一组sql语句保证同时成功或者失败。

一致性:数据库的约束,例如索引,在数据库状态转变前后没有发生变化。

隔离性:并发控制,读写,常用的四种隔离级别。

持久性:事务一旦提交,永久保存,即使数据库故障也能恢复。

原子性、持久性通过redo log日志实现,一致性通过undo log日志实现。

隔离性通过视图实现。

2.redo log

redo分为两部分,一部分在内存redo log buffer,一部分持久化在文件系统redo log file。

innodb引擎允许手动调整fsync操作,事务提交的时候,不写入redo log file,等待一个时钟周期之后再做fsync操作,fsync是性能瓶颈,可以显著提高数据库的性能。

参数innodb_flush_log_at_trx_commit=1 事务提交就调用刷盘fsync。

innodb_flush_log_at_trx_commit=0,事务提交不写入redo log file,而innodb的主线程 master thread 每一秒进行一次 redo log file 的 write 以及fsync 操作。

innodb_flush_log_at_trx_commit=2,事务提交时候写入redo log file,仅仅写入文件系统的缓存中,不进行fsync,只要os不宕机,还可以恢复。

三种状态:

写到redo log buffer

write:写到文件系统缓存(和buffer速度差不多)

fsync:写到磁盘

没有提交的事务,其redo log 也可能刷盘了,有三种情况:

innodb_flush_log_at_trx_commit=0,周期性刷盘。

buffer占用的空间达到innodb_log_buffer_size的一半,会触发write,写入文件系统缓存。

其他事务提交,携带该事务的buffer持久化到磁盘。

redo log实现原子写的原因:redo log的日志块单位为512字节,如果日志大于此就需要分割,而磁盘块单位也是512,因此不需要双写技术就可以保证原子性。

log buffer类似一个数组,元素就是日志块,log_block_hdr_no记录日志写到的位置,log buffer循环使用。

log buffer的刷盘时机:

事务提交;有一半空间被使用;到达check point。

LSN:日志序列号,单调递增,占用8字节,包含的信息有:写入的日志总量,check point的位置,日志的版本号。在重做的时候,LSN作为判断依据来刷盘,小于LSN的证明已经被刷盘了。

3.undo log

undo log需要随机读写。

主要用于回滚,回滚之后物理上不一定相同,比如数据在页面的位置发生变化,保证逻辑上相同,undo log是逻辑日志。

undo log可以用非锁定方式实现mvcc。

undo log本身也会产生redo log。

事务提交的时候,innodb引擎会做以下的事情:

将undo log放入列表,供之后的purge操作。判断undo log所在的页是否可以重用,可以的话分配给下一个事务使用,具体是:如果undo log所在页使用小于3/4,可以接着写。

undo log页被放入一个链表中,由purge线程判断这些页面是否可以删除,可能有其他事务需要使用这些页面。

对insert 语句的undo log,由于对其他事务不可见,可以在undo log提交后直接删除,不需要进行purge操作。

update undo log记录的是delete以及update对应的undo log,对其他事务可见,由purge线程决定最后是否删除。

merge操作延迟更新数据,同时也延迟产生undo log。

4.bin log

bin log是在事务commit的时候写;而redo log是在事务进行的过程中不断写,并且是并发的。

bin log在事务的执行过程中写入bin log cache,在事务提交的时候写入bin log文件。每个线程都有一份bin log cache,使用bin_log_cache_size控制,如果超过,需要先写到临时文件(也在磁盘)。提交时候写到公用的bin log文件,并清空cache。

两过程:

write:写到bin log cache,没有持久化到磁盘

fsync:把cache持久化到磁盘。

参数sync_binlog:

0:每次事务提交只write

1:每次事务提交write和fsync

N:累计N个事务fsync一次,有丢失风险。

注意:和redo log写机制的不同在于:redo log是有主动写到临时文件系统缓存(内存)的机制,而bin log是到了容量自动写到磁盘临时文件。

双1配置和两阶段提交的关系:

两阶段提交:redo prepare,bin log commit,事务 commit。

双1配置:innodb_flush_log_at_trx_commit=1 事务提交就调用刷盘fsync,实际上是:后台1秒轮询的线程刷盘,保证在prepare阶段redo log已经刷盘了。sync_binlog=1,bin log每次都刷盘。

bin log的格式:statement,row,mixed

statement格式原封不动记录,在主备同步情况下有二义性,例如sql语句中使用了where,其中有两个索引判断,两个库执行的时候,索引的选择不一定一样。

row格式会解析语句,用专用的命令记录,例如以上多索引可能的时候,记录主键id,这样避免了二义性,row格式日志本身很占用空间。

mixed,mysql自己判断是否会产生二义性,会就使用row,不会就使用statement。

5.组提交

事务提交时候redo log的两阶段:将操作记录到redo log buffer中;刷盘。刷盘阶段速度慢,组提交就是攒够一阶段的多个事务,一起做一次刷盘。

具体是由LSN实现,多个事务来的时候,第一个称为leader,它去刷盘的时候,携带的LSN为多个事务buffer长度之和,写完返回,多个事务也可以一并返回。节省了磁盘的IOPS。

两阶段提交中的组提交(拖时间攒数据):

方法:对binlog和redolog都采用组提交。redo log prepare阶段的write(写到文件缓存);bin log的write(写到缓存);redo log prepare阶段的fsync(刷盘);bin log的fsync(刷盘);commit。

redo log和bin log的顺序写以及组提交机制能大幅度减少磁盘的IOPS是WAL技术的重点!

6.长事务

对长事务,可以分批次来做,每次把成功的部分记录到表格中,中途出错回滚的代价可以减小。

posted @ 2022-05-08 10:28  来写代码了  阅读(80)  评论(0)    收藏  举报