MySQL事务

MySQL事务

事务是数据库区别于普通文件系统的重要特性之一。当写文件的时候,如果突然掉电,没有保存的数据就有可能丢失。

什么是事务

事务:Transaction 是数据库管理系统执行过程中的一个逻辑单位,不可再进行分隔。简单而言就是一组(包含多个或者一个)DML语句,要么全部执行成功,要么全部执行失败,不存在部分执行成功,部分执行失败这样的中间状态。

为什么需要事务

在我们日常的业务程序中,不可避免的会在一个会话中,执行多条DML语句,为了保证在发生异常后,数据库的数据状态还是正常的,这个就需要事务的保证。

事务的特性(ACID)

事务具备四个特性,也就是常说的ACID:

  • 原子性:也就是最基本的特征,使用begin开启一个事务,使用rollback回滚事务,使用commit提交事务,在开启事务和提交 / 回滚事务之间可以写很多条sql,这些sql在逻辑上是一个整体,是不可再分的,要么全部成功,要么全部失败。最主要的就是发生了异常可以全部回滚,这个特性是依靠undo log实现的。
  • 一致性:事务执行前后,数据库的数据状态从一个一致性状态转移到另一个一致性状态。
  • 持久性:事务一旦提交或者回滚,事务造成的结果,最终将持持久化到数据库中。持久性也分为不同的级别,innodb存储引擎提供了多种选择策略,持久性依靠redo log实现。
  • 隔离性:不同的事务执行过程中理论上是相互隔离的,这个只是一种期许,需要在隔离性和并发能力之间进行权衡。

事务的分类

  • 扁平事务:最基本也是最常见的,由begin开始,由commit / rollback结束。两者之间的所有操作归于一个原子操作。
  • 带有保存点的扁平事务:相比扁平事务,可以回滚到之前的某个点上,这个点称之为保存点。
  • 嵌套事务:在一个事务中,又开启了另外一个事务,外层的事务称为父事务,里层的事务称为子事务,子事务提交或者回滚之后,不会立即生效,还需要父事务提交或者回滚。
  • 分布式事务:分布式情况下的事务。

事务的实现

持久性的实现

持久性是依靠redo log实现的。记录物理页的变更操作,即使意外崩溃,也可以利用redo log完成恢复。只要commit的事务,即使发生了数据库崩溃,也依然可以利用redo log进行持久化。
mysql遵循日志先行,当commit的时候,此时数据还没有持久化到磁盘,先将redo log写入到重做日志文件中,为了保证os缓存中的redo log刷新到磁盘,还需要执行一次fsync操作。innodb存储引擎可以设置同步redo log到磁盘的策略,可以在持久性和效率之间进行权衡。为了保证持久性,不丢数据,最好还是在commit时就完成一次redo log的刷盘。redo log是一种物理日志,记录的是某个表空间,某个页,多少偏移量的数据发生了什么变更,这种写是一种顺序IO。在一个事务执行的过程中,会不断的写入redo log。在innodb存储引擎中,重做日志都是以512字节进行存储的,称为一个日志块,和一个扇区一样大小,因此在写入的时候可以保证原子性,不需要doublewrite技术。
如何判断是否需要崩溃恢复呢?innodb存储引擎引入LSN,代表日志序列号的缩写,重做日志有一个LSN表示一共写了多少字节的重做日志,每个页也有一个自己的LSN,当页的LSN小于重做日志的LSN的时候,就说明需要重做。
相较于binlog日志,redo log是存储引擎层的,binlog是服务层的,redo log记录的是物理日志,binlog记录的是逻辑日志,redo log会在一个事务的执行过程中不断产生,而binlog只有在事务提交的时候才会产生,另外redo log是幂等的。

原子性的实现

原子性最主要体现在发生异常后的回滚操作。原子性是依靠undo log实现的,undo log是逻辑日志,简单而言一个insert就对应一个delete,一个update对应相反的update…。另外MVCC也是依靠隔离性实现的。

事务的并发访问

MySql是一个CS架构的系统,允许多个会话同时访问,同时发起请求,因此当多个请求操作的是同一个记录的时候,就会有并发读写问题。理论上针对于这种情况(并发修改)为了保证数据的一致性,应该串行化执行,但是这样做对性能影响极大,为此mysql做了一些权衡,以尽可能的保证高性能及其数据的一致。

到底多个事务并发执行会造成什么影响呢?

  • 脏读:一个事务读到另一个事务没有提交的数据。
    在这里插入图片描述
    T1读到了T2还没有提交的数据,结果T2还进行了回滚,此时T1第二次查询到的数据就是错误的,这个是比较严重的。

  • 不可重复读: 同一个事务内,两次查询同一条记录结果获取到的数据不一样。这个现象便称为不可重复读。与脏读的区别是,不可重复读是读到了另一个事务已经提交的数据。
    在这里插入图片描述
    事务1在两次查询之间,事务2将该记录修改了,因此事务1两次查询的结果不一样。

  • 幻读:在同一个事务中,读取到之前没有出现的记录,强调的是记录。
    在这里插入图片描述
    幻读强调的是同一个事务多次读取记录时,出现了之前没有出现过的记录,因此如果事务2删除记录导致数据记录数变少其实不是幻读。

隔离级别

为了尽可能的提升性能,舍弃了一部分隔离性,SQL标准制定了4个隔离级别,隔离级别越低,数据库的性能越高。

  • 读未提交
  • 读已提交
  • 可重复读
  • 串行化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值