MySQL事务、事务实现的原理、隔离级别

事务的四大特性(ACID)

  1. 性(Atomicity): 事务是最⼩的执单位,不允许分割。事务的原性确保动作要么全部完成,要么完全不起作
  2. 致性(Consistency): 事务前后,数据保持致,多个事务对同个数据读取的结果是相同的;
  3. 隔离性(Isolation): 并发访问数据库时,户的事务不被其他事务所扰,各并发事务之间数据库是独的;
  4. 持久性(Durability): 个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发故障也不应该对其有任何影响。

并发事务带来的问题

脏读(Dirty read: 个事务正在访问数据并且对数据进了修改,这种修改还没有提交到数据库中,这时另外个事务也访问了这个数据,然后使了这个数据。因这个数据是还没有提交的数据,那么另外个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。

丢失修改(Lost to modify: 指在个事务读取个数据时,另外个事务也访问了该数据,那么在第个事务中修改了这个数据后,第个事务也修改了这个数据。这样第务内的修改结果就被丢失,因此称丢失修改。 例如:事务1读取某表中的数据A=202也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。

不可重复读(Unrepeatableread: 指在个事务内多读同数据。在这个事务还没有结束时,另个事务也访问该数据。那么,在第个事务中的两读数据之间,由于第个事务的修改导致第个事务两读取的数据可能不太样。这就发了在个事务内读到的数据是不的情况,因此称不可重复读。

幻读(Phantom read: 幻读与不可重复读类似。它发个事务(T1)读取了几行数据,接着另个并发事务(T2)插⼊了些数据时。在随后的查询中,第个事务(T1) 就会发现多了些原本不存在的记录,就好像发了幻觉样,所以称幻读。

MySQL底层实现事务的四大特性的方法

  • 原子性(隔离性)是undo log(回滚日志)实现的。
  • 一致性是由代码逻辑层面和其他三个特性保证的。
  • 隔离性是由mvcc实现的。
  • 持久性是基于redo log (重做日志)实现的。 
  • 持久性的实现:

基本的修改数据的过程为:

这样做有严重的性能问题:InnoDB在磁盘中存储的基本单元是页,可能本次修改只变更页一中几个字节,但是需要刷新整页的数据。一个事务可能修改了多页中的数据,页之间又是不连续的,就会产生随机IO。

为了解决上述问题,InnoDB提供了缓存解决这一问题(Buffer Pool),BP中包含了部分数据页的映射,作为访问数据库的缓冲;当从数据库读取数据时,会首先写入BP,BP中修改的数据会定期刷新到磁盘中(这一过程称之为刷脏

如果MySQL宕机,而此时BP中修改的数据还没有刷新的磁盘,就会导致数据的丢失,事务的持久性无法保证。

引入redo log(重做日志)是为了解决上述问题。 Redo Log记录的是物理日志,也就是磁盘数据的修改。当数据被修改时,除了修改BP中的数据,还会在redo log中记录这次操作,当事务提交时,会调用fsync接口对 redo log进行刷盘,如果MySQL宕机,重启时可以读取redo log中的数据,对数据库进行恢复,redo log采用的是WAL(Write-ahead logging,预写式日志), 所有修改先写入日志,再更新到磁盘。日志从redo log buffer 先write到文件系统的page cache,在fsync到磁盘。保证了数据不会因为MySQL宕机而丢失,从而满足了持久性的要求。引入重做日志后从磁盘加载数据到内存过程如下:

  • 在内存中修改数据
  • 把新数据写到Redo Log Buffer中
  • 把Redo Log Buffer中数据持久化到Redo Log文件中
  • 把Redo Log文件中数据持久化到数据库磁盘中

原子性的实现

实现原子性的核心就在于如何实现回滚,当事务回滚时能够撤销所有已经执行成功的SQL语句。InnoDB实现回滚,靠的是undo log。undo log属于逻辑日志,它记录的是SQL执行相关的信息。当事务对数据库进行修改时,InnoDB会生成对应的回滚日志。每条数据变更(insert/update/delete)操作都伴随一条undo log的生成,并且回滚日志必须先于数据持久化到磁盘上,undo log记录了数据被修改前的信息以及新增和被删除的数据信息。以update操作为例,当事务执行update时,其生成的undo log中会包含被修改行的主键(一遍知道修改了哪些行),修改了哪些列、这些列在修改前后的值的信息,回滚时便可以使用这些信息将数据还原到update之前的状态。回滚就是根据回滚日志做逆向操作,比如delete的逆向操作为insert,insert的逆向操作为delete,update的逆向为update等。如果事务执行失败或者调用了rollback,导致事务需要回滚,根据undo log生成回滚语句回滚到修改之前的样子

完整过程的顺序如下:


 

隔离性的实现

SQL 标准定义了四个隔离级别:

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

级别越低的隔离级别可以执行越高的并发,但同时实现复杂度以及开销也越大。

原子性,隔离性,持久性的目的都是为了要做到一致性。原子性和持久性是为了要实现数据的可性保障靠,隔离性是要管理多个并发读写请求的访问顺序。

READ UNCOMMITTED

READ UNCOMMITTED隔离级别下,事务中的修改即使还没提交,对其他事务是可见的。事务可以读取未提交的数据,造成脏读。因为读不会加任何锁,所以写操作在读的过程中修改数据,所以会造成脏读。好处是可以提升并发处理性能,能做到读写并行。换句话说,读的操作不能排斥写请求。

优点:读写并行,性能高
缺点:造成脏读

READ COMMITTED

一个事务的修改在他提交之前的所有修改,对其他事务都是不可见的。其他事务能读到已提交的修改变化。InnoDB在 READ COMMITTED中,使用排它锁,读取数据不加锁而是使用了MVCC机制。或者换句话说他采用了读写分离机制。但是该级别会产生不可重读以及幻读问题。这跟 READ COMMITTED 级别下的MVCC机制有关系,在该隔离级别下每次 select的时候新生成一个版本号,所以每次select的时候读的不是一个副本而是不同的副本。

在每次select之间有其他事务更新了我们读取的数据并提交了,那就出现了不可重复读。

REPEATABLE READ(Mysql默认隔离级别)

在一个事务内的多次读取的结果是一样的。这种级别下可以避免,脏读,不可重复读等查询问题。mysql 有两种机制可以达到这种隔离级别的效果,分别是采用读写锁以及MVCC。只要没释放读锁,在次读的时候还是可以读到第一次读的数据。
优点:实现起来简单
缺点:无法做到读写并行

  • 采用读写锁实现:只要没释放读锁,在次读的时候还是可以读到第一次读的数据。优点:实现起来简单。缺点:无法做到读写并行

  •  采用MVCC实现:多次读取只生成一个版本,读到的是相同数据。优点:读写并行缺点:实现的复杂度高。但是在该隔离级别下仍会存在幻读的问题。

SERIALIZABLE

该隔离级别理解起来最简单,实现也最单。在隔离级别下除了不会造成数据不一致问题,没其他优点。

 一致性的实现

  • 原子性,隔离性,持久性的目的都是为了要做到一致性。
  • 数据库本身提供保障,例如不允许向整形列插入字符串值、字符串长度不能超过列的限制等
  • 应用层面(代码层面)进行保障,例如如果转账操作只扣除转账者的余额,而没有增加接收者的余额,无论数据库实现的多么完美,也无法保证状态的一致

5分钟了解MySQL中的Buffer pool

MySQL事务实现原理详解

图解mysql事务实现原理

在Mysql中,事务是如何实现的呢?

MySQL的WAL(Write-Ahead Logging)机制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL事务隔离级别原理是基于并发控制来实现的。在MySQL中,有四个事务隔离级别:读未提交(Read Uncommitted)、读提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。每个隔离级别都有不同的数据可见性和并发控制机制。 在MySQL中,默认的隔离级别是可重复读(Repeatable Read),它通过使用多版本并发控制(MVCC)来实现。MVCC使用了两个关键的数据结构:Undo Log和Read View。 Undo Log是用于实现事务的回滚和并发控制的机制。当一个事务对数据进行修改时,会将旧版本的数据保存在Undo Log中,以便在事务回滚或其他事务需要访问该数据时使用。 Read View是每个事务的一个快照,用于确定事务可见的数据范围。每个事务开始时,会创建一个Read View,并根据事务隔离级别确定可见的数据范围。在可重复读隔离级别下,Read View会在事务开始时记录当前数据库中的所有活跃事务ID,并将这些事务对应的Undo Log应用到Read View中,从而确定事务能够看到的数据范围。 在并发执行的过程中,MySQL会根据不同的隔离级别事务的读写操作进行数据的读取和写入。对于读操作,会根据事务隔离级别和Read View进行判断,确定读取的数据是否可见。对于写操作,会使用锁机制和Undo Log来保证事务的一致性和隔离性。 需要注意的是,MySQL的不同存储引擎对事务隔离级别的支持也有所不同。例如,MyISAM引擎不支持事务,而InnoDB引擎则支持事务,并提供了更强的并发控制机制。 总结起来,MySQL事务隔离级别原理是通过使用多版本并发控制(MVCC)和锁机制来实现的。每个事务在开始时会创建一个Read View来确定可见的数据范围,同时使用Undo Log来支持事务的回滚和并发控制。不同的隔离级别会决定事务能够看到的数据范围和并发控制的方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值