关于MySQL事务的简单讲解

事务:
mysql要开始一个事务需要begin
扁平事务 不能提交或者回滚一部分,最常见的一种事务
三种结果 主动提交 (遇到错误)主动回滚  被动回滚 
带有保存点的扁平事务可以回滚一部分,保存点仅仅是一个标签,事务没提交前,一旦数据库崩溃,事务全部回滚,不会因为保存点而部分回滚
链事务(基本不用):应用于 一个大事务分多次提交, (提交释放锁资源),但是一个大事务多次提交缺不能回回滚
嵌套事务(MYSQL不支持嵌套事务 oracle支持):由若干个事务组成, 中间的部分事务提交 只要总的回滚,那么里面的事务也都会回滚


分布式事务:

核心是 一个事务跨两个数据库  
当一个事务跨两个数据库并且需要独自提交,这时候需要使用分布式事务 可以保证两事务同时提交或者回滚
但是MySQL支持的分布式事务并不好                                                                                                    
对于innodb支持 扁平 带有保存点的扁平 链事务 分布式事务



对于MySQL数据库来讲无论是事务还是sql都要尽可能的简单 。为了减少MySQL中的分布式事务等复杂事务我们可以在程序层面控制,将不同的商品放在不同的数据库中,避免一个事务同时访问两台数据库


对事务的实现必须要有redo 和undo

redo log 作用:
保证事务的持久性,
支持缓冲写
崩溃恢复(前滚恢复速度快,速度稳定,(速度主要取决于io))
redo 分为 两部分: 内存: redo log buffer
                   磁盘: redo log file

redo记录方式:
物理日志的记录方式(对某文件某个页所做的操作),不需要解析,
        
因为物理日志写的单元是512字节,所以不需要double write
redo保证了事务的持久性:
  原因:
日志先行
1、当事务提交的时候,会将redo log buffer中的日志写入到磁盘
2、当log buffer大小占用1/2的时候,会往磁盘里刷新
3、 数据写入磁盘的时候会触发检查点  log chechkpoint
所谓的检查点我们可以认为:
系统恢复的最早的那个点即写入到磁盘的最新脏块的redo log的位置(被记录到ibdata中即最早脏的那个数据块 系统崩溃恢复的时候,检查点作为崩溃恢复检查的起点)

redo 由两部分组成: redo log buffer 、 redo log file(区别与bin log)
通过 innodb_flush_log_at_trx_commit参数来控制写入重做日志的级别;默认值是1 
0:日志缓冲每秒一次地被写到日志文件,并且对日志文件做到磁盘操作的刷新,但是在一个事务提交不做任何操作。
1:在每个事务提交时,日志缓冲被写到日志文件,对日志文件做到磁盘操作的刷新。
2:在每个提交,日志缓冲被写到文件,但不对日志文件做到磁盘操作的刷新。对日志文件每秒刷新一次。网易技术部 67
默认值是 1,也是最安全的设置,即每个事务提交的时候都会从 log buffer 写到日志文件,而且会实际刷新磁盘,但是这样性能有一定的损失。
如果可以容忍在数据库崩溃的时候损失一部分数据,那么设置成 0 或者 2 都会有所改善。设置成 0,则在数据库崩溃的时候会丢失那些没有被写入日志文件的事务,最多丢失 1 秒钟的事务,
种方式是最不安全的,也是效率最高的。设置成 2 的时候,因为只是没有刷新到磁盘,但是已经写入日志文件,所以只要操作系统没有崩溃,那么并没有丢失数据 ,比设置成 0 更安全一些。

当我们批量导数据的时候可以将该参数改为0  (50W个insert 事务,设为1需要50秒,设为0仅需要13秒就可以完成)



redo  特点: 顺序写,在数据库正常运行情况下我们不去读脏块:
事务已经提交,redo log一定已经写入了磁盘
事务没有提交,脏块已经写入到了磁盘,redo log 一定写入到了磁盘
这个事务没有提交,因此回滚的数据一直存在,这个回滚的数据被redo log保护,,保证崩溃恢复的时候undo的正确回滚
事务没有提交,redo log也没有写入磁盘

innodb_log_group_home_dir,最好将redo放在写性能很高的磁盘 如ssd
innodb_log_file_in_group  设置redo file的每组多少个 建议设置5个,设置过低,当切换redo的时候,数据库会出出现短暂的停顿,。
保护了redo log就是保护了事务(redo log的保护比数据文件的保护还要重要)

binlog : 备份恢复, 主从复制   redo log 只对innodb引擎有效,bin log 对innodb 和 myism引擎都有效
redo log是基于页的物理记录方式即记录着该数据对应的页 行的地址,恢复的时候指定在哪恢复
bin log 逻辑层面 是基于语句级的记录方式
LSN号; 每条日志,每个数据页

每一个数据页,每一条日志都有lsn号 检查点也有lsn号  lsn号记录的就是数据的位置
 

double write技术
            
                        
redo lock
 
log group
mysql中,组之间是镜像关系
redo 的日志格式:

redo_log_type 重做日志的类型
space 表空间的ID     
page_no 页的偏移量
redo_log_body具体的操作格式




undo主要的三个作用:
1、事务回滚    
2、MVCC    
3、崩溃恢复
ibdata 共享表空间里第五个页是属于 undo的默认128个段
128个段各自又有多个块,
每个段的第一个块成为段头块
uodo的第一个块被称为系统事务表,分别指向不同段的段头块

段头块:
一个段头块最多可以有1024的slot(可以认为每个段最多可以有1024个事务,即一个数据库最多可以并发128*1024个事务)


一个事务的起始、
事务开始是会生成一个事务id:xid(依次递增),在系统事务表里找到一个相对空闲(活跃事务较少的段)的undo段,将自己的xid写进段头块的一个空闲槽位slot,事务修改数据前,将数据存放到空闲的块中,需要多个块的时候,地址依次相连(undo块使用了链条进行链接),最后一个用到的块会指向段头块的那个槽位
commit: 修改slow 已提交
rollback:
事务没有被提交,slot不会被覆盖,undo块不会被覆盖
找到最后一个块,依次往前回滚
所以如果是一个大事务,回滚时间会很长

崩溃恢复,回滚完,开始前滚,记录了事务的最大id,那说明所有未提交的事务都小于该id
但是并不会马上回滚,当新的事务修改数据块时,发现该数据块的事务未提交,就会前去回滚



事务提交但是没被写入磁盘需要redo 前滚,有些事务没提交但是被写入磁盘则需要undo回滚
undo 段 默认128个 
undo页需要回收。 通过purge线程 
同时支持的活动事务的数量 =undo段数*1024
可以用py_innodb_page_info.py工具来查看当前共享表空间的undo的数量

history list: 
按照事务提交的顺序将已提交的事务连起来,(这些事务也都分别对应着自己的undo块),当我们在purge清空回收undo块的时候,会根据history list 的顺序从尾端依次清空,即先清空事务最早的提交的undo块
关于MySQL事务的简单讲解

show engine innodb status 在transactions中可以监控到history list的长度,当这个长度增长较快的时候
说明数据库undo的刷新可能出现了问题这时可以考虑是否有大量的未提交的事务

表示该数据库的undo已经刷新到了1793,这个事务id, 也就是比这个事务id还小的事务都已经执行

关于MySQL事务的简单讲解
通过以下参数来控制undo
innodb_undo_directory :可以设置undo段文件所在的路径(默认在默认表空间里可以通过修改路径将其放在单独的文件中)
innodb_undo_logs : 设置回滚段的个数(最大值就是128)
innodb_undo_tablespaces  :用来设置构成undo段的文件的数量,即将undo段分配到多个文件里因为下面已经设置了多个raid所以该参数没哟多大意义


关于内存中undo 页的回收即purge 是一个磁盘离散读取的过程消耗Io为了节约undo采用了重用模式,即一个undo页如果备用空间小于3/4那么其他的事务也可以将undo数据存放到该页上节约undo的占用空间
关于事务控制: auto_commit自动提交的原因是 mysql在解决锁的问题上压力很大 

上一篇:1个月超14万人申请,数字经济之城杭州用新技术弹性限行


下一篇:分布式事务解决方案——柔性事务与服务模式