事务的四大特性 - ACID

  • 原子性 - Atomicity
    • 一个事务是一个不可分割的工作单位,事务中的所有操作要么都完成,要么全都不做;如果事务中的一个sql语句执行失败,所有已执行的语句必须回滚,数据库退回到事务发生之前的状态。
    • 实现原理:undo log - 回滚日志
      当事务对数据库进行修改时,InnoDB会生成对应的undo log;如果事务执行失败或调用了rollback,则InnoDB会根据undo log的内容做与之前相反的工作。
  • 持久性 - Durability
    • 事务一旦提交,对于数据库的改变应该是永久性的,接下来的其他操作或故障不应该对其有任何影响。
    • 实现原理:redo log - 重做日志
      向数据库写入数据时,会首先写入缓存Buffer Pool,Buffer Pool中修改的数据会定期刷新到磁盘中(刷脏),若MySQL宕机,缓存中的数据未来得及刷新到磁盘,数据就会丢失,导致持久性无法保证。
      引入redo log,当数据修改时,先在redo log中记录这次操作,再修改Buffer Pool中的数据。事务提交时,redo log会保存到磁盘,若MySQL宕机,则重启时可以读取redo log中的数据对数据库进行恢复。
      刷脏是以页为单位写入磁盘的,因此一个小修改也要整页写入,而redo log只包含真正需要写入的部分,无效IO大大减少。
  • 隔离性 - Isolation
    • 事务内部操作与其它事务是隔离的,隔离性追求的是并发情形下事务之间互不干扰。
    • 锁机制 隔离性要求同一时刻只能有一个事务对数据进行写操作,事务在修改数据前需要获得相应的锁,并且只有当事务提交后,锁才会释放。MyIsam只支持表锁,InnoDB同时支持表锁和行锁,一般情况使用行锁。
    • 并发情况下读操作可能出现三种问题:
      • 脏读
        当前事务可以读到其它事务未提交的数据(脏数据)
      • 不可重复读
        在一个事务中先后两次读取同一个数据,读取结果不同,即读到其它事务修改并提交的数据。
      • 幻读
        在一个事务中先后两次查询数据库,两次查询到的条数不同,即读取到其它事务插入/删除并提交的数据。
    • 事务隔离级别
      图片加载失败
      • MySQL默认隔离级别是可重复读,InnoDB下不会出现幻读(MVCC)。
  • 一致性 - Consistency
    • 指事务结束后,数据库的完整性约束没有被破坏,事务执行前后都是合法的数据状态。
    • 实现一致性的措施包括:
      • 保证原子性、持久性和隔离性。
      • 数据库本身对数据更改进行限制。
      • 应用层面进行保障。

MVCC - 多版本并发控制

  • 全称 Multi-Version Concurrency Control,使得MySQL在RR的隔离级别下解决脏读、不可重复读、幻读的问题。
  • 实现机制:创建一致性视图
    • 事务创建一致性视图时,会读取到已分配的事务的版本,记录最早事务的版本和最晚事务的版本。
      • 若数据修改的版本早于最早事务的版本,则数据可读;
      • 若数据修改的版本晚于最晚事务的版本,则数据不可读;
      • 若数据修改的版本处于最早和最晚之间:则该数据版本对应的事务若已提交,则可读,否则不可读。
    • 事务仅在第一次使用select语句进行读操作时创建一致性视图,假设有A事务早于B事务开始,但B事务修改数据并提交后A事务才第一次使用select语句读取数据,则会读取到B事务修改的数据。
      图片加载失败
  • MVCC仅针对读操作(SELECT),写操作不创建一致性视图(UPDATE, INSERT, DELETE)。