Mysql-事务特性、事务的隔离级别、以及ACID实现原理

事务是什么?

事务是一个最小的不可再分的工作单元;假定转账为例,A给B转账100元,A的账户需要扣100元,B的账户需要增加100元。这两个操作组合起来就是一个事务。

为什么需要事务?

如果没有事务,假设A扣款100元,数据库发生故障,B账户+100元的操作没有完成,而A却扣款了100元,这样就造成了客户的损失。这种一半成功、一半失败的状态是我们所不能忍受的,所以我们需要事务,事务可以帮助我们在做一组操作时,要么全部成功、要么全部失败,不会产生中间态,从而保证我们的数据一致性。

为什么事务可以保证数据一致性?

上面我们说到了事务的操作不存在中间态、要么全部成功,要么全部失败。那么事务为何可以如此?下面我们谈一谈事务的四大特性(简称ACID)

1.原子性(Atomicity)

何为原子性,原子性意味着一个事务中的所有操作不会出现中间态、要么全部成功要么全部失败,如果成功数据会被成功提交;如果失败数据会被回滚到事务开始前的状态,就和没发生过一样。

2.一致性(Consistency)

何为一致性?一致性表示我们的所有数据必须符合我们预期的结果,就像上述转账的例子,A的账户必须扣100元,B的账户必须加100元;不可以是101元或是其他结果,结果必须精确无误。所谓一致性就是数据的一致性。

3.隔离性(isolation)

何为隔离性,隔离性表示事务必须是独立的,多个事务之间不可以相互影响,一个事务不能受别的事务影响而导致数据的不一致性。

4.持久性(Durability)

何为持久性?持久性代表一旦事务被提交,那么这个数据的变更就是永久的变更,不会因为故障导致数据丢失。

由此可见,事务的ACID保证了数据的强一致性。


事务的隔离级别

事务有4大隔离级别,分别对应不同的应用场景

1.读未提交(Read uncommitted)

顾名思义,会读出还未被提交事务的数据,可能发生脏读、幻读、不可重复读的情况。(很少有情况会选用此隔离级别,因为数据安全性不高)

2.读已提交(Read committed)

只读已提交事务的数据,可能发生幻读、不可重复读。

3.可重复读(Repeatable read)

表示一个事务中多次读取数据的结果是一致的,可能发生幻读,也是mysql的默认事务隔离级别。(大部分情况选用此隔离级别)

4.串行化(Serializable)

表示事务将不再并发执行、执行完一个事务才会去执行下一个事务。不会发生任何数据问题,但效率过低,一般不考虑使用。

*脏读、幻读、不可重复读的解释

1.脏读

脏读指的是未被提交的数据也可以被读取

2.不可重复读

不可重复读指的是一个事务中进行多次查询但查询结果不一致。

3.幻读

幻读是一种特殊的情况,打一个比方,好比第一眼望过去只有两个人,再回头看一眼就变成了三个人,多出来的那个人好像鬼魅一样出现,一个事务在前后两次查询同一范围的时,后一次查询看到了前一次查询没有看到的行就是幻读。


事务的开始、事务的提交、事务的回滚

1.开启一个事务

Begin 或 Start Transaction开启一个事务;

2.提交一个事务

commit命令提交一个事务;

3.回滚一个事务

rollback命令回滚一个事务;

Begin #开始一个事务
select name from stu;#事务操作1
update stu set name = 'ok';#事务操作2
rollback;#回滚事务
commit;#提交事务

Mysql ACID是怎么实现的,它的实现原理是什么?

1、原子性(A)

首先要说明的是,为什么mysql能保证原子性,换一个说法就是为何可以回滚到事务开始前的数据。这一点似乎很好理解,当开始一个事务时,我们把原本的记录记录下来不就好了吗?没错,下面我们来探讨mysql是如何进行存储的。

undo log保证了原子性,当一个事务开启时,Mysql会将这些数据与sql写到undo log中,如果事务需要回滚,我们就可以利用undo log的sql与数据将其执行反向操作,比如Insert执行delete,Update同样对应Update将其数据恢复原样,有此机制我们就能保证事务的原子性。

2.隔离性 (I)

事务如何保证隔离性呢?在mysql中隔离性是用MVCC(多版本并发控制)保证的,我们给与每一个事务一个唯一的ID,且ID是绝对递增的,那么在MVCC中的操作描述如下(在mvcc中每一行记录会增加两个隐藏的字段,一个是行的创建版本号,另一个是行的删除版本号)

  • 当事务中执行select操作时,行的创建版本号必须小于等于(<=)当前事务的ID 并且 行的删除版本号要么未定义,要么大于(>)当前事务版本号。
  • 当事务中执行Insert操作时,将当前事务ID给到行的创建版本号。
  • 当事务中执行delete操作时,将当前事务ID给到行的删除版本号。
  • 当事务中执行update操作时,新增一条记录,并将当前ID给行的创建版本号;将老的记录的删除版本号定义为当前事务版本号。

以此为基础,我们就能保证每个事务的隔离性。

3.持久性 (D)

mysql中,持久性的保障是由redo log做的,每当commit一个事务时,会将此事务做的变更写入redo log(磁盘)中,这意味着当mysql故障时我们也可以通过redo log恢复数据。

4.一致性(C)

一致性由原子性、隔离性、持久性共同保障。


版权声明:本文为qq_43163317原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。