Mysql——事务机制原理

Mysql——基本日志常识

日志分类

普通日志

二进制日志(bin log)、错误日志、查询日志、慢查询日志

事务日志

redo log——重做日志,来记录已成功提交事务的修改信息
undo log——回滚日志,主要记录的是数据的逻辑变化,为了在发生错误时回滚之前的操作,需要将之前的操作都记录下来,然后在发生错误时才可以回滚

事务日志——数据结构

其实除了我们在数据库中定义的列之外,每一行中还包含了几个隐藏列:

**row_id**:行记录的唯一标志	row_id是行记录的唯一标志,也没有申明唯一索引的情况MySQL才会添加这个隐藏列
**transaction_id**:事务ID		事务中产生了增删改,则会分配一个事务id来区分不同行
**roll_pointer**:回滚指针		指向该记录对应的undo log;一个有undo log组成的链表,这个undo log链表其实就是这条记录的版本链

事务日志——持久化

持久化时机

insert undo log是指在insert 操作中产生的undo log
update undo log记录的是对delete 和update操作产生的undo log

持久化过程

Buffer Pool中修改的数据会定期刷新到磁盘中(这一过程称为刷脏)
先从Buffer Pool中读取,如果Buffer Pool中没有,则从磁盘读取后放入Buffer Pool

持久化调优

innodb_flush_log_at_trx_commit:0 定时缓存、即可调用fsync()写入到log file on disk,会丢失一秒数据
innodb_flush_log_at_trx_commit:1 即可缓存、即可刷新,不会丢失 每次提交都会将log buffer中的日志写入os buffer并调用fsync()函数刷到log file on disk
innodb_flush_log_at_trx_commit:2 即可缓存、定时调用fsync()写入到log file on disk,会丢失一秒数据

Mysql——并发读隔离原理(1)——事务隔离级别

Read uncommitted(读未提交)

在这个隔离级别下,事务的修改即使没有提交,对其他事务也是可见的。事务可以读取未提交的数据,这也被称之为脏读。这个级别会带来很多问题,从性能上来说,READ UNCOMMITTED不会比其他的级别好太多,但是却会带来很多问题,除非真的有非常必要的理由,在实际应用中一般很少使用。

Read committed(读提交)

大多数数据系统的默认隔离级别都是REDA COMMITED(MySql不是),REDA COMMITED满足前面提到的隔离性的简单定义:一个事务开始时,只能看到已经提交的事务所做的修改。换句话说,一个事物从开始直到提交前,所做的修改对其他事务不可见。这个级别有时候也叫做不可重复读,因为执行两次相同的查询可能会得到不同的结果。

Repeatable read(可重复读取)

REPEATABLE READ解决了脏读以及不可重复度的问题。该级别保证了同一个事务多次读取同样记录的结果是一致的。但是理论上,可重复度还是无法解决另外一个幻读的问题。所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,就会产生幻行。
不可重复读跟幻读的区别在于,「前者是数据发生了变化,后者是数据的行数发生了变化」。

Serializable(可序化)

SERIALIZABLE是最高的隔离级别,它通过强制事务串行执行,避免前面说的幻读。简单来说SERIALIZABLE会在读取的每一行数据上都加锁,所以可能会导致大量的超时和锁争用的问题。实际应用中也很少使用这个隔离级别,只有在非常需要确保数据一致性而且可以接受没有并发的情况下,才考虑此级别。

Mysql——并发读隔离原理(2)——并发读分类

当前读指令

【激活方式】
select lock in share mode(共享锁),
select for update ;
update, insert ,delete(排他锁)
【特殊运行】
这些操作都是一种当前读,为什么叫当前读?
就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。

快照读指令

【激活方式】
事务中直接select,第二次再select就会快照读,激活方式就是普通查询不加for update和读锁,
【特殊运行】
即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本,不会并发读写阻塞

Mysql——并发读隔离原理(3)——快照读原理(MVCC多版本并发控制)

继续顺延mysql中的并发读中的快照读原理的实现
MVCC主要解决的问题就是
(1)RR模型中事务中读取的变量只重复读第一次的,保证事务的正常,不能一会儿是这个值,一会是另外一个值
(2)解决当前读中的阻塞问题

步骤(1)生成快照(数据库级别)

快照生成方式

RC隔离级别下,每一次select都会生成并获取最新的Read View;此时遍历数据只过滤读未提交的数据
RR隔离级别下,第一次select生成一次Read View,事务执行的比照基础一直是这个Read View

快照数据结构

整体信息:m_ids,数据库中正在执行事务的id集合
整体信息:m_up_limit_id:数据库中正在执行事务的id集合的最小值,
整体信息:m_low_limit_id :数据库中系统id的下一个id数字
单行信息:m_creator_trx_id:当前事务的id,又叫快照的id

步骤(2)遍历数据(数据行级别)

遍历数据行伪代码

每次遍历数据行的变量是row,row的tx_version_id判断本行数据对该事务是否可见
for(;;){
	if(changes_visible(row.tx_version_id,tableName)){
		return row;
	}
	row=row.next
}

在这里插入图片描述
可见性检查逻辑

主要是利用事务id的递增特性,来区分数据行的事务版本对应和事务操作的先后顺序
注意,RR模式下,每次select时快照仍然一致,但是数据的链表可能发生了变化

【每遍历一次】

	数据的事务id=(快照生成时)创建该快照的事务id(当前事务)————自己在操作自己的数据————数据行可见
	数据的事务id<(快照生成时)正在执行的事务id集合最小(不存在trIds)————该数据在快照生成前就插入提交了————数据可见
	数据的事务id>(快照生成时)当时系统分配将要分配的事务id————该数据在快照生成后才插入————数据不可见
	数据的事务id $(快照生成时)正在执行的事务id集合所有值————该数据在快照时事务还在运行(正运行)——————数据不可见
	数据的事务id!$(快照生成时)正在执行的事务id集合所有值————该数据在快照时事务已经停止(已提交)——————数据可见

【不可见逻辑】
在这里插入图片描述
根据roll_pointer继续沿着链表遍历,判断可见性直到找到一个可见的就将数据返回

Mysql——事务回滚管理(待更新)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值