提纲:

🔥事务 & 锁 & 日志

  • 事务 ACID

  • InnoDB 引擎对 ACID 的实现

  • 并发问题与解决

🎈面试八股真题——在【Java八股-第二十八期】优化 中总结

一、事务 & 锁 & 日志

1. 事务 ACID

  • 1、Atomic 原子性:事务中所有 sql 语句是一个不可拆分的整体,要么同时失败,要么同时成功

  • 2、Consistency 一致性:事务前后数据总量不变,例如转账

  • 3、Isolation 隔离性:由存储引擎的事务隔离级别决定

  • 4、Durable 持久性:事务对数据的修改会持久化存储到磁盘

2.InnoDB 引擎对 ACID 的实现

  • 1、原子性:通过 undo-log 来实现数据的回滚

    • # InnoDB 中,事务每执行一条增删改语句,就将修改后的数据版本存储在 undo-log 版本链中,版本主要信息有数据的主键 ID/事务的 ID/回滚指针,当需要进行回滚时,就会根据回滚指针找到事务开始前的数据版本进行回滚

  • 2、持久性:通过 redo-log 来实现

    • #InnoDB 中,对数据的修改是在 InnoDB 缓存中修改的,修改后的数据会在 MySQL 空闲时由后台线程刷入磁盘,在这期间,这部分数据就是脏数据,InnoDB 引擎通过在执行修改后,将数据拷贝至 redo-log buffer 中,并默认每隔 1 秒刷入磁盘,并在事务提交时,在将 bin-log 刷入磁盘后,为 redo-log 中的数据添加 commit 标记,记录事务成功提交,当 MySQL 宕机导致缓存中的脏数据丢失时,就可以通过 redo-log 进行数据恢复,保证事务的持久性

  • 3、隔离性:见下文

  • 4、一致性:当前原子性与隔离性保证时,一致性自然保证

3.并发问题与解决

  • 并发问题

    • 1、数据更新丢失,当并发事务指令交错时,就可能造成 A 对数据的修改被 B 覆盖

    • 2、脏读,事务 A 读取了事务 B 修改后还未提交的数据,并在这个数据上进行事务,然而事务B 最后执行失败进行了回滚,可能导致数据总量前后不一致等问题

    • 3、不可重复读,比如有一个事务 A,选择一条数据进行修改,并且修改的条件是性别为男,A 读取了数据后,判断为男性,此时 B 事务将性别修改为女并提交,在 A 进行修改时,就会发现数据前后不一致,从而修改失败

    • 4、幻读,幻读与不可重复读的区别在于,不可重复读主要由于数据前后不一致,幻读主要由于数据前后的存在性不一致,例如有事务 A 要添加一条数据,添加前先根据主键进行判断,判断不存在后,还没有来的及添加,事务 B 此时将这条数据加入了表并提交,导致事务 A 添加失败

  • 隔离级别

    • 1、读已提交

    • 2、可重复读

    • 3、串行化

  • InnoDB 的实现

    • MVCC

      • 对于 Select 操作,InnoDB 默认使用 MVCC 的不加锁的思想,来实现读已提交和可重复读的隔离级别

      • 原理