mysql事务的四个特点和实现原理

目录

1.事务的相关概念

事务的四个特性

并发事务带来的问题

事务的隔离级别

事务实现的原理

2.二阶段提交

为什么要二阶段提交?

在两阶段提交的情况下,是怎么实现崩溃恢复的呢?


1.事务的相关概念

事务的四个特性

关系型数据库(例如:MySQL、SQL Server、Oracle 等)事务都有 ACID 特性:

  • 原子性(Atomicity):事务是最小的执行单位不允许分割。事务的原子性确保动作要么全都成功,要么失败回滚。
  • 一致性(Consistency):事务执行前后,数据保持一致。例如转账业务,无论操作是否成功,转账者和收款者的账户总额是不变的。
  • 隔离性(Isolation):多个事务并发访问数据库时,一个事务不受其他事务的影响,各个并发事务之间数据库是独立的。
  • 持久性(Durability):一个事务提交之后,对数据库中数据的改变是持久的,即使数据库发生故障也不会对其产生任何的影响。

并发事务带来的问题

  • 脏读: 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
  • 不可重复读:指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读 。
  • 幻读:幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
  • 丢失修改:指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务 1 读取某表中的数据 A=20,事务 2 也读取 A=20,事务 1 修改 A=A-1,事务 2 也修改 A=A-1,最终结果 A=19,事务 1 的修改被丢失。

事务的隔离级别

  • READ-UNCOMMITTED(读取未提交):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
  • READ-COMMITTED(读取已提交):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
  • REPEATABLE-READ(可重复读):对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • SERIALIZABLE(可串行化) :最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
隔离级别脏读不可重复读幻读
READ-UNCOMMITTED
READ-COMMITTEDx
PEREATABLE-READxx
SERIALIZABLExxx

mysql的默认隔离级别是什么?

MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重复读)。我们可以通过SELECT @@tx_isolation;命令来查看,MySQL 8.0 该命令改为SELECT @@transaction_isolation;

在这里插入图片描述

 隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是 READ-COMMITTED(读取提交内容) ,但是 InnoDB 存储引擎默认使用 REPEATABLE-READ(可重复读) 并不会有任何性能损失。

事务实现的原理

  • A原子性:由undo log(回滚日志)日志保证,它记录了需要回滚的日志信息,事务回滚时撤销已经执行成功的sql。例如:
    (1)当你delete一条数据的时候,就需要记录这条数据的信息,回滚的时候,insert这条旧数据
    (2)当你update一条数据的时候,就需要记录之前的旧值,回滚的时候,根据旧值执行update操作
    (3)当年insert一条数据的时候,就需要这条记录的主键,回滚的时候,根据主键执行delete操
    undo log记录了这些回滚需要的信息,当事务执行失败或调用了rollback,导致事务需要回滚,便可以利用undo log中的信息将数据回滚到修改之前的样子。
  • C一致性:由其他三大特性保证、程序代码要保证业务上的一致性
  • I隔离性:由MVCC来保证。
  • D持久性:由内存+redo log(重做日志)来保证,mysql修改数据同时在内存和redo log记录这次操作,宕机的时候可以从redo log恢复。mysql先把磁盘上的数据加载到内存中,在内存中对数据进行修改,再刷回到磁盘上。如果此时突然宕机,内存中的数据就会丢失。如下图所示,如果路径1过程中宕机了,则数据就会丢失。 
    于是,mysql采用redo log解决数据丢失的问题,当做数据修改的时候,不仅在内存中操作,还会在redo log中记录这次操作。当事务提交的时候,会将redo log日志进行刷盘(redo log一部分在内存中,一部分在磁盘上)。当数据库宕机重启的时候,会将redo log中的内容恢复到数据库中,再根据undo log和binlog内容决定回滚数据还是提交数据。
    :路径1是随机IO,速度较慢。路径2在写redo log的时候只有追写(append)操作,所以路径2为顺序IO,速度快于路径1,所以大多数情况下,在路径1断电的时候,redo log已经写入完成。

2.二阶段提交

 InnoDB在写redo log时,并不是一次性写完的,而有两个阶段,Prepare与Commit阶段,这就是"两阶段提交"的含义。

为什么要二阶段提交?

redo log与binlog都写一次的话,也就是存在以下两种情况:

  • 先写binlog,再写redo log:当前事务提交后,写入binlog成功,之后主节点崩溃。在主节点重启后,由于没有写入redo log,因此不会恢复该条数据。而从节点依据binlog在本地回放后,会相对于主节点多出来一条数据,从而产生主从不一致。
  • 先写redo log,再写binlog:当前事务提交后,写入redo log成功,之后主节点崩溃。在主节点重启后,主节点利用redo log进行恢复,就会相对于从节点多出来一条数据,造成主从数据不一致。

因此,只写一次redo log与binlog,无法保证主节点崩溃恢复与从节点本地回放数据的一致性。

在两阶段提交的情况下,是怎么实现崩溃恢复的呢?

首先比较重要的一点是,在写入redo log时,会顺便记录XID,即当前事务id。在写入binlog时,也会写入XID。因此存在以下三种情况:

  • 如果在写入redo log之前崩溃,那么此时redo log与binlog中都没有,是一致的情况,崩溃也无所谓。
  • 如果在写入redo log prepare阶段后立马崩溃,之后会在崩恢复时,由于redo log没有被标记为commit。于是拿着redo log中的XID去bin log中查找,此时肯定是找不到的,那么执行回滚操作。
  • 如果在写入bin log后立马崩溃,在恢复时,由redo log中的XID可以找到对应的bin log,这个时候直接提交即可。

总的来说,在崩溃恢复后,只要redo log不是处于commit阶段,那么就拿着redo log中的XID去binlog中寻找,找得到就提交,否则就回滚。在这样的机制下,两阶段提交能在崩溃恢复时,能够对提交中断的事务进行补偿,来确保redo log与binlog的数据一致性。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值