请你谈谈数据库事务机制?

1事务实现方式-MVCC(多版本并发控制)

MVCC是MySQL的的多版本并发控制即multi-Version Concurrency Controller,MVCC解决的问题是什么? 数据库并发场景有三种,分别为:
1、读读:不存在任何问题,也不需要并发控制
2、读写:有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读、幻读、不可重复读
3、写写:有线程安全问题,可能存在更新丢失问题
MVCC是一种用来解决读写冲突的无锁并发控制, 也就是为事务分配单项增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照,所以MVCC可以为数据库解决以下问题:
1、在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并
发读写的性能
2、解决脏读、幻读、不可重复读等事务隔离问题,但是不能解决更新丢失问题

MVCC最大的好处:读不加锁,读写不冲突,极大的增加了系统的并发性能。

两种读的方式:1快照读:读取的是历史版本的记录; SQL语句:select …
2当前读:读取的是最新版本的记录;SQL语句:1select … lock in share mode; 2select … for update; 3update 4delete 5insert;

引例:

事务A事务B
selectselect
update -> commit
select (可以读到最新版本的记录吗?)

RC: 是可以读到的
RR: 是读不到的 --------> 这时为什么?引出MVCC(多版本的并发控制机制)【可见性算法】

MVCC实现原理是什么?

mvcc的实现原理主要依赖于记录中的三个隐藏字段,undo log,readView来实现的。

1隐藏字段

行记录都会包括用户看不到隐藏字段:

{
1.DB_TRX_ID:最后一次创建修改该记录的事务ID
2.DB_ROW_ID:隐藏的主键ID
3.DB_ROLL_PTR:回滚指针+undo log
}

2对undo log的理解

undo log被称之为回滚日志:当进行insert操作的时候,产生的undo log只在事务回滚的时候需要,并且在事务提交之后可以被立刻丢弃;当进行update和delete操作的时候,产生的undo log不仅仅在事务回滚的时候需要,在快照读的时候也需要,所以不能随便删除,只有在快照读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除(当数据发生更新和删除操作的时候都只是设置一下老记录的deleted_bit, 并不是真正的将过时的记录删除,因为为了节省磁盘空间,innodb有专门的purge线程来清除deleted_bit为true的记录,如果某个记录的deleted_id为true,并且DB_ TRX_ ID相对于purge线程的read view可见,那么这条记录一定时可以被清除的)

:回滚日志,数据历史版本的状态。
事务1

nameagegenderDB_TRX_IDDB_ROW_IDDB_ROLL_PTR
zhangsan11man11null

事务2

nameagegenderDB_TRX_IDDB_ROW_IDDB_ROLL_PTR
lisi11man21ox123(事务1的行记录的地址)

事务3

nameagegenderDB_TRX_IDDB_ROW_IDDB_ROLL_PTR
wagnwu11man31ox456(事务2的行记录的地址)

…依次,形成一个链表:当不同的事务对同一条数据修改,会导致该记录的undo log形成一个线性链表,其中链表首部:最新的历史版本记录。链表尾部:多个历史版本最早的历史记录。

提出一个问题:name接下来的事务4(新事务),读的是哪一版本的记录?这里是有一定的规则的,下面详细介绍。

3readView

Read View是事务进行快照读操作的时候生产的读视图,Read View的最大作用是用来做可见性判断的,也就是说当某个事务在执行快照读的时候,对该记录创建一个Read View的视图,把它当作条件去判断当前事务能够看到哪个版本的数据,有可能读取到的是最新的数据,也有可能读取的是当前行记录的undo log中某个版本的数据。

事务进行快照读,产生的视图。主要包括以下字段:

{
1.trx_list: 系统活跃的事务ID
2.up_limit_id:列表中最小的事务ID
3.low_limit_id:系统尚未分配的下一个事务ID
}

实际场景:

事务1事务2事务3事务4
开启开启开启开启
update
快照读(能不能读取到修改的记录值)
{
1.trx_list: 1,2,3
2.up_limit_id:1
3.low_limit_id:5
}

DB_TRX_ID:4

这里引入一个算法:

1、首先比较DB_TRX_ ID < up_ limit_ id,如果小于,则当前事务能看到
DB_ TRX_ ID所在的记录,如果大于等于进入下一个判断;

2、接下来判断DB_ TRX_ ID >= low_ limit id,如果大于等于则代表
DB_ TRX_ ID所在的记录在Read View生成后才出现的,那么对于当前事
务肯定不可见,如果小于,则进入下一步判断;

3、判断DB_TRX_ ID是否在活跃事务中:
如果在,则代表在Read View生成时刻,这个事务还是活跃状态,还没有commit, 修改的数据,当前
事务也是看不到;
如果不在,则说明这个事务在Read View生成之前就已经开始commit,那么修改的结果是能够看见的。

所以,快照读是可以读到最新的记录。

这里解释两个重要概念:

RC&&RR

因为Read View生成时机的不同,从而造成RC、RR级别下快照读的结果的不同。

1.在RR级别下的某个事务对某条记录的第一次快照读会创建一个快照即Read View:将当前系统活跃的其他事务记录起来,此后在调用快照读的时候,还是使用的是同一个Read View,所以只要当前事务在其他事务提交更新之前使用过快照读,那么之后的快照读使用的都是同一个Read View,所以对之后的修改不可见。

3、在RC级别下,事务每次快照读都会新生成一个快照和Read View,这就是我们在RC级别下的事务中可以看到别的事务提交的更新的原因。

总结:在RC隔离级别下,是每个快照读都会生成并获取最新的Read View;而在RR隔离级别下,则是同一个事务中的第一个快照读才会创建Read View,之后的快照读获取的都是同一个Read View.

2事务的ACID实现原理

1(Atomicity)原子性 : 事务是最小的执行单位,不允许分割。原子性确保动作要么全部完成,要么完全不起作用;
2(Consistency)一致性:一致性代表了底层数据存储的完整性, 事务系统通过保证事务的原子性,隔离性和持久性来满足这一要求执行事务前后,数据保持一致;
3(Isolation)隔离性: 并发访问数据库时,一个事务不被其他事务所干扰。
4(Durability)持久性: 一个事务被提交之后,对数据库中数据的改变是持久的,即使数据库发生故障。

原子性由undo log日志来保证,它记录了需要回滚的日志信息,事务回滚时撤销已经执行成功的sql;
一致性是由其他三大特性保证,程序代码要保证业务上的一致性;
隔离性是由MVCC来保证;
持久性由redo log来保证,mysq|修改数据的时候会在redo log中记录一份日志数据, 就算数据没有保存成功,只要
日志保存成功了,数据仍然不会丢失;引出对redo log的理解:

redo log

这里要提到一个WAL(write ahead log)预写日志----先写日志,再写磁盘。因为随机读写的效率要低于顺序读写,先将数据通过顺序读写的方式写到日志文件中,然后再将数据写入到对应的磁盘文件中,这个过程:顺序的效率要远远高于随机的效率,换句话说,如果实际的数据没有写入到磁盘,只要日志文件保存成功了,那么数据就不会丢失,可以根据日志来进行数据的恢复。

引出一个两阶段提交:MySQL本身就存在一个bin log日志,而innodb本身也存在redo log日志。因为两种日志属于不同的组件,所以为了保
证数据的一致性,要保证bin log和redo log一致,所以有了二阶段提交的概念。

写redo log 处于prepare状态 ——>写bin log——>提交事务,处于commit状态。

3事务的隔离级别

MySQL定义了四种隔离级别,包括一些具体规则, 用于限定事务内外哪些改变是可见的,哪些改变是不可见的。
低级别的隔离一般支持更高的并发处理,并且拥有更低的系统开销。
在这里插入图片描述

隔离级别

READ UNCOMMITTED 读取未提交内容:在这个隔离级别,所有事务都可以"看到"未提交事务的执行结果。

READ COMMITTED 读取提交内容:大多数数据库系统的默认隔离级别(但是不是MySQL的默认隔离级别),满足了隔离的早先简单定义:一个事务开始时,只能”看见”已经提交事务所做的改变:一个事务从开始到提交前,所做的任何数据改变都是不可见的,除非已经提交。这种隔离级别也支持所谓的“不可重复读"。这意味着用户运行同一个语句两次,看到的结果是不同的。

REPEATABLE READ 可重复读:MySQL数据库默认的隔离级别。在并发读取事务时,会看到同样的数据行,不过这会导致另外一个棘手问题”幻读"。通过多版本并发控制机制解决了幻读问题。

SERIALIZABLE可串行化:该级别是最高级别的隔离级。它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简而言之,SERIALIZABLE是在每个读的数据行上加锁。在这个级别,可能导致大量的超时Timeout和锁竞争Lock Contention现象。

导致问题

脏读是指一个事务读取了未提交事务执行过程中的数据。

不可重复读是指对于数据库中的某个数据,一个事务执行过程中多次查询,返回不同结果。这就是在事务执行过
程中,数据被其他事务提交修改了。

不可重复读同脏读的区别在于,脏读是一个事务读取了另一未完成的事务执行过程中的数据,而不可重复读是一个
事务执行过程中,另一事务提交并修改了当前事务正在读取的数据。

幻读是一个事务内读取到了别的事务插入的数据,导致前后读取不一致

幻读和不可重复读都是读取了另一条已经提交的事务,所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值