Mysql学习(事务篇)

  • 事务的隔离级别有哪些?MySQL的默认隔离级别是什么?
  • 什么是幻读,脏读,不可重复读呢?
  • MySQL事务的四大特性以及实现原理
  • MVCC熟悉吗,它的底层原理?

MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你需要删除人员的基本资料。也要删除和该人员相关的信息,如信箱,文章等等,这些数据库操作语句就构成一个事务。

ACID 事务基本要素

  • A(Atomicity) 原子性,整个事务中的所有操作,要么全部完成,要么全部不完成,事务在执行过程中发生错误,会被回滚。
  • C(Consistency)一致性:在事务开始之前和事务结束后,数据库的完整性约束没有被破坏。
  • I(Isolation)隔离性 一个事务的执行不能其他事务干扰,即一个事务内部的操作和使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能互相干扰
  • D(Durability)持久性:在事务完成以后,该事务所对数据库所做的更改,便持续的保存在数据库之中,并不会被回滚

并发事务处理带来的问题

  • 更新丢失  事务A和事务B选择同一行,然后基于最初选定的值更新该行时,由于两个十五都不知道彼此的存在,就会发生丢失更新问题
  • 脏读 事务A读取了事务B更新的数据,然后事务B回滚了,那么A读取到数据是脏数据
  • 不可重复读:事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据做个更新并提交,导致事务A多次读取同一数据时,结果不一致。
  • 幻读:幻读与不可重复度类似,它发生在一个事务A读取了几行数据,接着另一个并发事务B插入了一些数据时,在随后的查询时,事务A就会发现多了一些原本不存在的记录,就好像发生了幻觉一样

幻读和不可重复读的区别:

不可重复读注重的是修改了数据

幻读的重点是在新增或者删除了数据

并发事务处理带来的问题的解决办法:

  • 一种是加锁:在读取数据前,对其加锁,阻止其他事务对数据进行修改。

  • 另一种是数据多版本并发控制(MultiVersion Concurrency Control,简称 MVCC 或 MCC),也称为多版本数据库:不用加任何锁, 通过一定机制生成一个数据请求时间点的一致性数据快照 (Snapshot), 并用这个快照来提供一定级别 (语句级或事务级) 的一致性读取。从用户的角度来看,好象是数据库可以提供同一数据的多个版本。

事务隔离级别

  • 读未提交:最低的隔离级别,允许读取尚未提交的数据变更。
  • 读已提交:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读和不可重复读还有可能发生
  • 可重复读:对一个字段的多次读取结果都是一直的,除非数据是被本身事务自己修改的,可以阻止脏读和不可重复读,(mysql默认的事务隔离级别)
  • 可串行化,最高级别
show variables like 'tx_isolation'

MVCC多版本并发控制

Mysql的大多数事务型存储引擎实现都不是简单的行级锁,基于提升并发性考虑,一般都同时实现了多版本并发控制(MVCC)

可以认为MVCC是行级锁的一个变种,但它在很多情况下避免了加锁操作,因此开销更低,虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只是锁定必要的行。

MVCC的实现是通过保存数据在某个时间点的快照来实现的,也就是说不管需要执行多长时间,每个事务看到的数据都是一致的。

典型的MVCC实现方式,分为乐观并发控制悲观并发控制

InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存行的过期时间,当然存储的并不是真的时间,而是系统版本号,每开始一个新的事务,系统版本号都会自动递增,事务开始时刻的系统版本好,用来和拆线呢到的每行记录的版本号进行比较。

REPEATABLE READ(可重读)隔离级别下MVCC如何工作:

  • SELECT

    InnoDB会根据以下两个条件检查每行记录:

    只有符合上述两个条件的才会被查询出来

    • InnoDB只查找版本早于当前事务版本的数据行,这样可以确保事务读取的行,要么是在开始事务之前已经存在要么是事务自身插入或者修改过的

    • 行的删除版本号要么未定义,要么大于当前事务版本号,这样可以确保事务读取到的行在事务开始之前未被删除

  • INSERT:InnoDB为新插入的每一行保存当前系统版本号作为行版本号

  • DELETE:InnoDB为删除的每一行保存当前系统版本号作为行删除标识

  • UPDATE:InnoDB为插入的一行新纪录保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为删除标识

MVCC 只在 COMMITTED READ(读提交)和REPEATABLE READ(可重复读)两种隔离级别下工作。

事务日志

InnoDB 使用日志来减少提交事务时的开销,因为日志中已经记录了事务,就无须在每个事务提交时把缓冲池的脏块刷新到磁盘中。

事务修改的数据和索引通常会映射到表空间的随机位置,所以刷新这些变更到磁盘需要很多随机IO。

InnoDB假设使用常规磁盘, 随机IO比顺序IO昂贵得多,因为一个IO请求需要时间把磁头移动到正确得位置,然后等待磁盘上读出需要的部分,再转到开始位置。

InnoDB 用日志把随机IO变成顺序IO。一旦日志安全写到磁盘,事务就持久化了,即使断电了,InnoDB可以重放日志并且恢复已经提交的事务。

InnoDB 使用一个后台线程智能地刷新这些变更到数据文件。这个线程可以批量组合写入,使得数据写入更顺序,以提高效率。

事务日志可以帮助提高事务效率:

  • 使用事务日志,存储引擎在修改表的数据时只需要修改其内存拷贝,再把该修改行为记录到持久在硬盘上的事务日志中,而不用每次都将修改的数据本身持久到磁盘。

  • 事务日志采用的是追加的方式,因此写日志的操作是磁盘上一小块区域内的顺序I/O,而不像随机I/O需要在磁盘的多个地方移动磁头,所以采用事务日志的方式相对来说要快得多。

  • 事务日志持久以后,内存中被修改的数据在后台可以慢慢刷回到磁盘。

  • 如果数据的修改已经记录到事务日志并持久化,但数据本身没有写回到磁盘,此时系统崩溃,存储引擎在重启时能够自动恢复这一部分修改的数据。

事务的实现

事务的实现是基于数据库的存储引擎,不同的存储引擎对事务的支持程度不一样,Mysql中支持事务的存储引擎有InnoDB和NDB

事务的实现就是如何实现ACID特性

事务的隔离性是通过锁实现,而事务的原则性,一致性,和持久性则是通过事务日志实现的。

事务是如何通过日志来实现的

事务日志包括重做日志redo 和回滚日志undo

redo log (重做日志) 实现持久化和原子性

在innodb的存储引擎中,事务日志通过重做日志和innoDB存储引擎的日志缓存(InnoDB Log Buffer)实现。事务开启时,事务中的操作,都会先写入存储引擎的日志缓存中,在事务提交之前,这些缓冲的日志都需要提前刷新到磁盘上持久化,这就是DBA中常说的日志先行。当事务提交之后,在Buffer Pool中映射的数据文件才会慢慢刷新到磁盘,此时如果数据库崩溃或者宕机,那莪当系统重新启动进行恢复时,就可以根据redo log中记录的日志,吧数据库恢复到崩溃前的一个状态,未完成的事务,可以继续提交,也可以选择回滚,这基于回复的策略而定的。

在系统启动的时候,就已经为redo log 分配了一块连续的存储空间,以顺序追加的方式记录Redo Log,通过顺序IO来改善性能,所有的事务共享redo log的存储空间,他们的Redo log按照语句的执行顺序,依次交替的记录在一起。

undo log(回滚日志)  实现一致性

undo log 主要为事务的回滚服务,在事务执行的过程中,除了记录redo log,还会记录一定量的undo log,undo log记录了数据在每个操作前的状态,如果事务执行过程中需要回滚,就可以根据undo log 进行回滚操作,单个事务的回滚,只会回滚当前事务做的操作,并不会影响到其他的事务做的操作。

undo记录的时一部分完成并且写入硬盘的未完成的事务,默认情况下回归日志时记录在表空间中的。

二种日志均可以视为一种恢复操作,redo_log是恢复提交事务修改的页操作,而undo_log是回滚行记录到特定版本。二者记录的内容也不同,redo_log是物理日志,记录页的物理修改操作,而undo_log是逻辑日志,根据每行记录进行记录。

 

分布式事务采用两段式提交(two-phase commit)的方式:

  • 第一阶段所有的事务节点开始准备,告诉事务管理器ready。

  • 第二阶段事务管理器告诉每个节点是commit还是rollback。如果有一个节点失败,就需要全局的节点全部rollback,以此保障事务的原子性。

Guess you like

Origin blog.csdn.net/Chen_leilei/article/details/112462209