mysql基础-事务篇

158 阅读6分钟

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战

定义

mysql事务是一组sql语句组成的逻辑处理单元,只要勇于处理操作量大,复杂度搞的数据。典型的场景是银行转账,账户A给账户B转账,必须要保证账户A减去的相应的金额,账户B增加了相应的金额,只有都操作成功了,才是一次事务完成

事务的特征(ACID)

原子性(Atomicity): 整个事务的所有操作,要么全部完成,要么全部失败,不能停留在中间某个环节。如果事务执行过程中发生错误,会被回滚到事务开始前的状态

一致性(Consistency): 事务在开始和结束后,数据库的完整性约束没有被破坏

隔离性(Isolation): 一个事务的执行不会被其他的事务干扰。即一个事务的内部操作与其他并发事务的操作是相互隔离,互不干扰

持久性(Durability): 在事务完成后,该事务对数据库所做的更改持久的保存在数据库中,不会被回滚

并发事务带来的问题

  1. 更新丢失(Lost Update): 事务A和事务B选择同一行,然后基于最初选定的值更新该行时,两个事务都不知道彼此的存在,就会发生更新丢失的问题
  2. 脏读(Dirty Reads): 事务A读取了事务B更新的数据,然后事务B做了回滚操作,那么事务A读取到的数据是脏数据
  3. 不可重复度(Non-Repeatable Reads): 事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据做了更新并提交,导致事务A多次读取同一数据时,结果不一致。
  4. 幻读(Phantom Reads): 幻读与不可重复度类似。他发生在一个事务A读取了几行数据,接着另外一个并发事务B插入了一些数据,在随后的查询中,事务A会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

事务隔离级别

  1. Read-Uncommitted(读未提交):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读和不可重复读
  2. Read-Committed(读已提交):允许并发事务已经提交的数据,可以阻止脏读,但是幻读和不可重复读人有可能发生
  3. Repeatable-read(可重复读):对同一个字段的多次读取结果都是一致的,除非数据被本身事务自己所修改,可以阻止脏读和不可重复读,但是幻读仍有可能发生。这也是mysql的 默认隔离级别
  4. 可串行化:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰。该级别可以阻止脏读、不可重复读、幻读。

查看当前数据库的隔离级别

-- 5.7.20版本之前的写法
-- 方式一
show variables like 'tx_isolation';
-- 方式二
select @@tx_isolation;

-- 5.7.20版本之后的写法
-- 方式一
show variables like 'transaction_isolation';
-- 方式二
select @@transaction_isolation;

事务日志

InnoDB的事务操作原理

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

  • 事务修改的数据和索引通常会映射到表空间的随机位置,所以刷新这些变更到磁盘需要很多随机IO。随机IO比顺序IO昂贵得多,因为一个IO请求需要把磁头一到正确的位置,然后等待磁盘上读出需要的部分,再转到开始位置。

  • InnoDB用日志把随机IO变成顺序IO。一旦日志安全写到磁盘,事务就持久化了,及时断电了,InnoDB重启可以通过redo log恢复已经提交的事务

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

事务的实现

  • 事务的实现是基于数据库的存储引擎实现的,不同的存储引擎对事务的支持程度不一样
  • 事务的实现就是实现ACID特性。事务隔离性是通过锁实现,而事务的原子性、一致性和持久性则通过事务日志来实现。

事务的种类

  • redo log(重做日志)
  • undo log(回滚日志)

redo log实现持久性和原子性

  1. 在InnoDB引擎中,事务日志通过redo log和日志缓冲(InnoDB Log Buffer)实现
  2. 事务开启时,事务中的操作,都会先写入存储引擎的日志缓存中,在事务提交之前,这些缓存的日志都需要提前刷新到磁盘上持久化,这就是日志先行(Write-Ahead logging)
  3. 当事务提交之后,在Buffer Pool中映射的数据文件会慢慢的刷新到磁盘。此时如果宕机,那么系统重启进行恢复时,可以根据redo log中记录的日志,把数据库恢复到崩溃前的一个状态。未完成的事务,可以继续提交或者选择回滚,这基于恢复的策略而定
  4. 在系统启动的时候,就已经为redo log分配了一块连续的存储空间,以顺序追加的方式记录redo log,通过顺序IO改善性能。所有事务共享redo log的存储空间,他们的redo log按照语句的执行顺序,依次交替的记录在一起。

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

  1. undo log主要为事务的回滚服务
  2. undo log 记录了数据在某个操作前的状态,如果事务执行过程中需要回滚,就可以根据undo log进行回滚操作
  3. undo log记录的是已部分完成未写入磁盘的未完成的事务 4.单个事务的回滚,不会影响到其他事务做的操作。

redo log和undo log的区别

  1. 两种日志都是为了恢复操作
  2. redo log是恢复提交事务修改的页操作。而undo log是回滚行记录到特定版本
  3. 两者记录的内容也不同,redo log是物理日志,记录页的物理修改操作。而undo log是逻辑日志,根据每行记录继续记录。