数据库事务

事务:一系列操作的集合。

 

事务应当满足的四大特性(ACID):

1. 原子性(Atomicity):不可分割,要么同时成功,要么同时失败。

2. 一致性(Consistency):事务操作前后数据总量不变。

3. 隔离性(Isolation):事务之间各自独立,不会相互影响。

4. 持久性(Durability):当事务结束后,数据库会持久化的保存数据。

 

并发情况下事务引发的问题:

--脏读:当前事务执行完第一次查询后,另一个事务对数据进行了修改但未提交,此时当前事务第二次执行相同的查询出现不同的结果,导致读不一致问题。

--不可重复读:当前事务执行完第一次查询后,另一个事务对数据进行了修改或删除并已提交,导致当前事务第二次执行相同的查询出现不同的结果,导致读不一致问题。

--幻读:当前事务执行完第一次查询后,另一个事务进行了插入操作并已提交,导致当前事务第二次执行相同的查询出现不同的结果,导致读不一致问题。

(脏读和不可重复读是针对update/delete语句的修改带来的读不一致问题;幻读是针对insert语句的修改带来的读不一致问题)

 

数据库隔离级别:

1. read uncommitted:存在脏读、不可重复读、幻读问题
2. read committed:存在不可重复读、幻读问题

3. repeatable read:存在幻读问题(例外:innodb引擎的repeatable read隔离级别就已经解决了幻读问题,达到了serializable级别的标准)

4. serializable:解决了所有的问题

 

MVCC(Multi Version Concurrency Control,多版本并发控制)

MVCC是InnoDB引擎实现 read committed和repeatable read隔离级别的底层机制。

InnoDB为其表中的每行数据维护了一个版本链。我们可以将每行记录看作为一条链表,链表的每个节点为该行数据的不同版本。链表的表头节点为该行记录的最新版本,而往后的每个节点为按时间从近到远的顺序的不同版本的该行数据。当对某行数据执行了update或delete操作时,就会使得该行数据产生一个新的版本,被链接在链表最前端(不管当前事务有没有提交,都会生成相应版本。若事务回滚,则该事务所产生的版本都会从链表中被移除)。通过update操作产生的版本,其会复制该行记录的链头的版本,并修改相应字段,作为新的链头;通过delete操作产生的版本,其会复制该行记录的链头的版本,并将版本的delete_flag置true,作为新的链头。

具体地,InnoDB会为每行数据自动维护两个隐藏字段——DB_ROLL_PTR和DB_TRX_ID。DB_ROLL_PTR字段中存储的是指向该行数据的上一个版本的指针,而该行数据上一个版本的数据中的DB_ROLL_PTR字段又会指向该行数据上上个版本,以此形成了一条版本链。DB_TRX_ID字段则记录了当前版本是由哪个事务生成的(字段中记录的是对应事务的事务id)。

补:事务id的分配机制:当事务中第一次执行insert/delete/update操作时,InnoDB将会为该事务分配一个id。事务id的分配是递增的,先执行增删改操作的事务的事务id一定小于后执行增删改操作的事务的事务id。

 

 

 

InnoDB会为select语句生成一个一致性视图ReadView。对于repeatable read隔离级别,事务中所有的select语句都将使用第一次执行select语句时生成的ReadView(因此每次select出来的内容一定是相同的)。对于 read committed隔离级别,每次select都会重新生成ReadView(因此每次select出来的内容不一定相同)。

当生成ReadView时,主要是生成如下4个内容:

·m_ids:当前所有未提交的事务的事务id。

·min_id:即m_ids中的最小值。

·max_id:当前所有事务(已提交和未提交)的最大事务id。

·creator_trx_id:生成该ReadView的事务的事务id。

 

一个事务的事务id若小于min_id,则表示该事务在该ReadView被创建时已经提交了;

一个事务的事务id若在min_id和max_id之间,且不在m_ids中,则表示该事务在该ReadView被创建时已经提交了;

一个事务的事务id若在min_id和max_id之间,且存在m_ids中,则表示该事务在该ReadView被创建时还未提交;

一个事务的事务id若大于max_id,则表示该事务在该ReadView被创建时还未开启,是在ReadView被创建后才开启的。

 

在执行select语句时,InnoDB会根据该select语句的ReadView,来为表中的每行数据挑选出一个恰当的版本进行展示。

为每行数据挑选版本的过程:从该行数据的版本链链头开始遍历。根据遍历到的版本的DB_TRX_ID字段判断创建该版本的事务的类型。若为已提交事务,则当前版本对当前事务可见,停止遍历并选取该版本进行展示;若为未提交事务且并非当前事务,则当前版本对当前事务不可见,继续往后遍历。若为未提交事务且是当前事务,则当前版本对当前事务可见,停止遍历并选取该版本进行展示;若为未开始事务,则当前版本对当前事务不可见,继续往后遍历。

 

对于read uncommitted隔离级别,每行记录就只一个版本,任何的修改操作都将直接修改该版本,任何的读取操作也是读取该版本的数据。对于serializable隔离级别,其是通过加锁的方式,使得所有操作串行执行,从而保证了读一致性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值