MySQL事务

67 阅读4分钟

来源

  1. # 03 | 事务隔离:为什么你改了我还看不见?
  2. 08 | 事务到底是隔离的还是不隔离的?

事务

事务特性

  • 特性:ACID(Atomicy 原子性,Consistency 一致性,Isolation 隔离性,Durability 持久性)
  • 事务启动:事务并不是在begin语句就启动,而是在其后的第一个SQL启动
  • 支持:只有InnoDB支持,MyISAM支持
  • 查看隔离级别:show variables like 'transaction_isolation'
  • 原子性:由undo保证; 持久性:由redo保证; 隔离性:由undo+事务ID+mvcc保证; 一致性:由程序保障+AID,一致性是我们最终的目的。
  • 事务启动时机:begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个操作 InnoDB 表的语句,事务才真正启动。如果你想要马上启动一个事务,可以使用 start transaction with consistent snapshot 这个命令。
  • DDL语句不需要显示地使用begin/commit,本身就是一个事务

原子性

  • 即最小,不可再拆分。这些操作要么全部成功,要么全部失败回滚

一致性

  • 系统从一个正确的状态迁移到另外一个状态。它依赖于应用层,即由开发者保证。ACID就是说事务能够通过AID来保证C这个过程

持久性

  • 事务一旦被提交,那么对数据库的改变是永久性的

隔离性

  • 隔离级别:设置在数据库上的参数
    • 读未提交(read uncommited):一个事务还没提交,它做的变更就能被其他事物看见
    • 读提交(read commited):一个事务提交之后,它做的变更才能被其他事物看见
    • 可重复读(repeatable read):一个事务在执行过程中看到的数据,总是跟事务启动时看到的数据一致。未提交的变更对其他事物也不可见,简称RR。
    • 串行化(serializable):对同一行记录,"写"会加"写锁","读"会加"读锁"。读写锁冲突时,后访问的事务必须等前一个事务完成
    • 注意:自己更新的数据,总能看见
  • 问题
    • 脏读(dirty read):当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问并且使用了这个数据
    • 不可重复读(non-repeatable read):在一个事务内,两次读到的数据不一致
    • 幻读(phantom read):
  • 底层实现:
    • 创建视图:"读未提交" 没有视图的概念,"可重复读" 是在事务开启前创建视图,"读提交" 是在每句SQL执行前创建,"串行化" 采用加锁来避免并行访问
    • " 视图 " 概念
      • 一是 view。它是一个查询语句定义的虚拟表,在调用的时候执行查询语句并生成结果
      • 二是InnoDB在实现MVVC时用到的 一致性视图 (consistent read view),用于RC(Read Commited)和RR(Repeatable Read)隔离级别实现
    • 实现方法(概念)
      • 回滚日志(undo log):每条记录在更新的时候都会记录一条回滚操作。记录最新的值,通过回滚操作都可以得到前一个状态的值。这样一个记录在系统中存在多个版本(不同的隔离级别下事务会选择到不同的版本),这就是数据库的多版本并发控制(MVCC)
      • 何时删除日志:系统自动判断,当没有事务需要用到回滚段时就删除。一个事务提交之前,数据库里它可能用到的回滚记录都必须保存,所以最好不要用长事务。避免长事务:set autocommit=1, 通过显式语句的方式来启动事务
      • 疑点:commit work and chain 语法
    • 快照在MVVC里如何实现 ?以RR隔离级别为例,读和更新会产生不同的效果
      • InnoDB里面的每个事务有唯一的ID,transaction id。在事务开始时向InnoDB事务系统申请,并且严格按照递增的
      • 每行数据是多版本的,每次事务更新都会生成一个新版本的数据,并把这个数据版本的事务ID赋值为transaction id,记为 row trx_id,而旧数据也要保留。但旧数据并不是直接保留,而是从当前版本通过回滚日志来计算得出
      • 以事务启动时刻为准,事务从当前版本往前找在这个事务启动之前的版本。为了实现,InnoDB为每个事务构造了一个数组,用于保存这个事务启动瞬间还未提交的事务ID。数组里面事务 ID 的最小值记为低水位,当前系统里面已经创建过的事务 ID 的最大值加 1 记为高水位。

MVVC