自学内容网 自学内容网

Mysql事务

目录

(一)事务的作用

(二)提交与回滚

(1)事务开启与提交

 (2)自动提交

(3)回滚方式

(三)事务四大特性(AICD)

(1)原子性(Atomicity)

undo log: 回滚实现

(2)一致性

(3)隔离性

3.1脏读

3.2不可重复读

3.3幻读

MVCC(解决脏读,不可重复读,幻读)

(4)持久性

redo log :持久实现

(一)事务的作用

事务是MySQL等关系型数据库,区别于其他NoSQL的重要特性:

事务:事务是数据库操作执行的最小单位,事务中包含一个至多个sql语句,这些语句要么全部执行,要么全部不执行

事务的主要作用是保证事件的一致性,例如在转账操作中,张三向李四账户转1000,那么张三账户就要减1000,李四账户就要加1000,不能张三账户里面减了1000,李四账户里面却没有加1000

(二)提交与回滚

(1)事务开启与提交

下方是事务开启的操作,start transaction标志事务开启,然后执行中间的sql语句,如果中间sql语句发生错误,则会发生回滚,撤销之前成功的操作。但一般不会这样用

start transaction;

#一到多条sql语句...

commit;

 (2)自动提交

mysql的事务提交方式默认采用的是自动提交,可以通过show variables like 'autocommit'命令来查看如图

可以看到自动提交是开启的

在自动提交状态下,每个单独的sql视为一个事务,会在执行后自动提交

 

 如果关闭自动提交模式就需要手动提交,可以通过 set autocommit = 0;来关闭自动提交模式如图

 在手动提交模式下,就需要使用start transaction来显示开启事务,多个sql语句视为一个事务,通过commit来提交命令,如果需要修改则可以使用rollback命令来撤销未提交的修改。

(3)回滚方式

mysql的回滚主要是通过日志来实现的,为方便叙述下面事务的四大特性,将日志回滚操作放在原子性中讨论。

(三)事务四大特性(AICD)

事务的四大特性即:原子性(Atomicity),一致性(Consistency),隔离性(Isolation),持久性(Durability),虽然说是事务的四大特性,但真正同时满足这四个特性的事务少只有很少,与其说是事务的四大特性,不如说是衡量事务的四大维度。

(1)原子性(Atomicity)

提到原子,我们的第一印象应该就是不可分割,虽然现在证明是可以再分的,但现在原子依然成为了不可分割的代名词,这正好对应了事务中的sql语句要么不做,要么全做的特性。

上面说过如果一个sql语句发生错误会让全部的操作回滚到事务开始之前的状态,这个操作是通过日志实现的,下面介绍回滚日志的操作过程

undo log: 回滚实现

undo log(回滚日志),是回滚实现机制的关键,当事务对数据库进行修改时,innodb(存储引擎)就会生成对应的undo log,如果事务执行失败需要回滚,就可以利用日志中的信息,将数据回滚到事务开启之前的样子。

例如执行的是一个insert 语句,undo log 会对应生成一个delete语句,回滚时执行这个delete语句。

(2)一致性

一致性:是指事务将数据库从一种状态转变为下一种一致的状态,在事务开始之前和事务开启之后,数据库的完整性约束没有被破坏

例如:表中有个姓名字段,有唯一性的约束(名字不能重复),但在事务提交或回滚之后,姓名的唯一性约束被破坏了(名字重复了),这就破坏了事务的一致性要求,因此事务是一致性的状态,如果事务中某个动作失败了,系统可以自动撤销事务——返回初始化的状态

(3)隔离性

隔离性是数据库在并发执行事务的时候所需要关注的问题,一般会分为四种隔离级别

读未提交(写的时候可以读,读的时候可以写)

读已提交(写的时候加锁不能读,读的时候可以写),

可重复读(写的时候加锁不能读,读的时候加锁不能写,但会写其他数据),

串行化(读和写完全隔离执行)

隔离级别就是我们在“数据可靠性”“效率”之间做权衡的方式,我们通常希望数据库的执行效率高,那就需要并发程度高,但高的并发可能会带来一些问题

我们先探讨,写操作(一个事务)对读操作(另一个事务)的影响

3.1脏读

事务A读到了事务B未提交的数据(脏数据),这种现象叫做脏读

可能出现脏读的隔离级别:读未提交 

3.2不可重复读

   不可重复读是指一个事务(事务A)内多次读取同一数据集合。但在这个事务还没结束时,另一个事务(事务B)也访问了同样的数据集合,并做了一些DML操作。因此,在第一个事务(事务A)读取的两次数据之间,由于第二个事务(事务B)的修改,导致第一个事务两次读取的数据可能是不一样的

脏读和不可重复读的区别是,脏读读的是未提交的数据,不可重复读,读取的是已提交的数据,但它违反了数据库事务一致性的要求

可能出现不可重复度的隔离级别:读未提交,读已提交

3.3幻读

 在事务A中按照条件(一般是范围查找),先后两次查询数据库,两次查询的结果集不同,这种现象称为幻读

不可重复读和幻读的区别可以理解为,不可重复读是数据变了,幻读是数据集合变了

可能出现幻读的隔离级别:读未提交,读已提交,可重复读 

MVCC(解决脏读,不可重复读,幻读)

MVCC:Multi-Version Concurrency Control,即多版本并发控制

这里的多版本指的是数据库中同时存在多个版本的数据,并不是整个数据库的多个版本,而是某一条记录的多个版本同时存在。

隐藏字段

MySQL 中的行数据,除了我们肉眼能看到的字段之外,其实还包含了一些隐藏字段,它们在内部使用,默认情况下不会显示给用户,其中包括版本号,更改时间啥的,这是实现多版本控制的关键。

MVCC 实现

MVCC 是 InnoDB 存储引擎的核心特性之一。通过使用 Undo log,MySQL 可以为每个事务提供独立的事务视图,使得事务读取数据时能看到一致且符合隔离级别要求的数据版本。

直接上例子


解决脏读 

 当事务A在T3时刻读取事务B中数据,发现数据已经被其他事务(事务B)修改于是就通过undo log 回滚,得到事务B修改之前版本的数据,从而避免了脏读。

一个形象的比喻就像,我想要读明朝的历史,你怎么把清朝的历史给我呈上来了,赶紧用undo log 给我回滚到明朝的历史让我读。

 解决不可重复读

当事务A在T2时刻读取到余额为100,这个数据的版本号是1,在T2时刻读取到余额是200,此时这个数据的版本号是2, 此时就会发现两次读取的数据版本号不一致,事务A就会通过undo log 进行回滚,得到版本号为1的数据,从而解决了不可重复读问题

 

解决幻读 

当事务A在T2节点第一次读取0<id<5数据时,标记的不只是id=1的数据,而是将范围(0,5)进行了标记,这样当T5时刻再次读取0<id<5数据时,便可以发现id=2的数据比之前标记的版本号更高,此时再结合undo log执行回滚操作,避免了幻读。

(4)持久性

定义:持久性是指,当事务对数据库进行修改后,这个修改是永久性的。这很好理解,毕竟数据都是存储再硬盘上的,事务完成修改后,就是在硬盘中完成了修改,硬盘中的数据是不会像内存一样丢失的。

redo log :持久实现

   在数据库中,如果每次的数据读取都是对磁盘进行IO操作,那么数据库的性能就十分受限,于是就引用了缓存,数据的读取会首先从缓存中读取,数据的插入也会首先插入到缓存中,等到了一定的时间再刷新到磁盘中(刷脏),但是缓存又带来了新的问题,如果数据库宕机之前,缓存中的数据没有及时刷新到磁盘中会导致数据丢失,这时就引入redo log(重做日志)来解决这个问题。

   当事务提交时,必须先将该事务的所有日志写入到重做日志文件中进行持久化,待事务的commit操作完成才算完成,为保证每次日志都能写入重做日志文件中,在每次将重做日志写入重做日志文件后,InnoDB存储引擎都需要调用一次fsync操作。

fsync操作:是指将内存中的数据(包括文件数据和元数据)强制写入到磁盘上,确保数据的持久性。



为什么用redo log 刷脏比用缓存刷脏快呢

(1)刷脏是随机IO,因为每次修改的数据位置随机,但写redo log是追加操作,属于顺序IO。

(2)刷脏是以数据页(Page)为单位的,MySQL默认页大小是16KB,一个Page上一个小修改都要整页写入;而redo log中只包含真正需要写入的部分,无效IO大大减少。


原文地址:https://blog.csdn.net/m0_73233932/article/details/142590825

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!