MySQL 事务机制

事务机制:

事务语法:

-- 开始事务
begin;
-- 或
start transaction;

-- 提交
commit;

-- 回滚
rollback;

-- 保存点
savepoint;

事务特性:

默认事务:

MySQL的事务 默认自动提交:在自动提交的状态下 每一条SQL就是一个事务 会被直接执行

手动开启事务后:则所有的SQL语句都在一个事务中 直到执行了commit或rollback

事务原则:
  1. 原子性(Atomicity)

    定义:

    • 原子性是指事务包括的所有操作要么成功 要么全部失败回滚

    实现:

    • InnoDB实现回滚 靠的是undo log(回滚日志)
    • 实现原子性的关键 是当事务回滚时能够撤销所有已经成功执行的sql语句
  2. 一致性(Consistency)

    定义:

    • 事务执行结束后 数据库的完整性约束没有被破坏 事务执行的前后都是合法的数据状态
      如果回滚数据 回滚的数据需要跟原来保持一致

      数据库的完整性约束包括但不限于:
      实体完整性(如行的主键存在且唯一)、列完整性(如字段的类型、大小、长度要符合要求)、外键约束、用户自定义完整性(如转账前后,两个账户余额的和应该不变)

    实现:

    • 保证原子性、持久性和隔离性 如果这些特性无法保证 事务的一致性也无法保证
    • 数据库本身提供保障,例如不允许向整形列插入字符串值、字符串长度不能超过列的限制等
    • 应用层面进行保障,例如如果转账操作只扣除转账者的余额,而没有增加接收者的余额,无论数据库实现的多么完美,也无法保证状态的一致
    • 一致性原则的维护相对于其他三个 更偏向数据的规范
  3. 隔离性(Isolation)

    定义:

    • 多个并发事务之间要相互隔离 对应的是MySQL的可串行化级别 但是在实际中 因为性能的原因很少使用可串行化级别

    实现:

    • (一个事务)写操作对(另一个事务)写操作的影响:锁机制保证隔离性
    • (一个事务)写操作对(另一个事务)读操作的影响:MVCC保证隔离性
  4. 持久性(Durability)

    定义:

    • 事务一旦被提交了 对数据库中的数据是永久性的 此时即使系统崩溃修改的数据也不会丢失

    实现:

    • 问题:InnoDB提供了缓冲池 虽然在性能方面带来了质的飞跃 但是当MySQL系统宕机、断电的时候可能会丢数据
      如果这个时候事务提交了 数据还未持久化到磁盘 那么数据也就会丢失
      因为我们的数据已经提交了 但此时是在缓冲池里头 还没来得及在磁盘持久化
      所以我们急需一种机制需要存一下已提交事务的数据 为恢复数据使用
    • 解决:redo log 重做日志
      虽然redo log和刷脏都是IO操作 但刷脏是随机IO 而redo log是追加操作属于顺序IO
      另外刷脏是以数据页为单位 一点小改动都需要整页写入 而redo log只包含真正需要写入的部分
事务状态:
  • Active:事务的初始状态,表示事务正在执行;
  • Partially Commited:在最后一条语句执行之后;
  • Failed:发现事务无法正常执行之后;
  • Aborted:事务被回滚并且数据库恢复到了事务进行之前的状态之后;
  • Commited:成功执行整个事务;
image-20210721225034057

隔离级别:

  1. 读未提交:
    • 概念:事务A可以读取到事务B修改过但未提交的数据 (没提交也能获取到数据
    • 问题:可能发生脏读、不可重复读和幻读问题 一般很少使用此隔离级别
  2. 读已提交
    • 概念:事务A只能在事务B提交后才能读取到事务B修改的数据 (提交后才能获取到
    • 问题:解决了脏读的问题 但可能发生不可重复读和幻读问题 一般很少使用此隔离级别
    • 加锁:数据的读取都是不加锁的 但是数据的写入、修改和删除是需要加锁的
  3. 可重复读 --MySQL的默认隔离级别
    • 概念:事务A在提交后 事务B也不能读取到事务A提交的修改 (开启后就不能获取到
    • 问题:解决了脏读和不可重复读的问题 可能发生幻读问题 实际开发级别
    • 加锁:数据的读写都是加锁的 不过是行锁 所以可以阻塞其他事务对于本事务内读数据的修改和删除 实现可重复读
      但是行锁只能控制修改和删除 而不能作用于新增 所以还是会出现幻读的现象 (应该是行锁 也可能是乐观锁 待确认)
  4. 可串行化
    • 概念:事务A提交前 事务B读写操作都会被阻塞 (事务只会一个一个的执行 只有都是读操作不会被阻塞)
    • 问题:各种问题(脏读、不可重复读、幻读)都不会发生 通过加锁实现(读锁和写锁) 出于性能考虑很少使用

事务并发:

并发问题:

  • 脏读:
    事务A读到了事务B未提交的数据 (如果最终事务B没有提交 那么这个数据就是不存在的)
    读取到不存在的数据 就是脏读

  • 不可重复读:
    在事务A执行过程中 事务B修改了事务A中读取的数据 导致事务A在前后读取的数据不一致
    (如果是两个同样条件的修改语句 出现不可重复读现象 会导致两条数据修改的结果不一致)
    重复读取数据不一致 就是不可重复读

  • 幻读:

    在事务A执行过程中 事务B添加了数据 添加的数据在事务A的读取范围内 导致事务A在前后读取到的数据不一致
    (同 不可重复读现象一样 会导致修改的数据结果不一致)
    读取到新增的数据 就是幻读

注意点:幻读和不可重复读的区别?

  • 幻读和不可重复读看起来很像 都是在事务执行中 被别的事务修改了读取的数据 导致前后数据不一致
    两者的区别在于
    • 不可重复读侧重于数据的修改
    • 幻读则是侧重于数据的新增
  • 原因:
    • 不可重复读没有对读操作的数据加锁 所以别的事务也可以修改 本事务读取的数据 最终造成不可重复读现象
    • 幻读对读数据加了锁 不过幻读的锁是行锁 所以只是不能修改删除而已 还是能添加 所以会出现幻读现象
      (应该是行锁 也可能是乐观锁 待确认)

并发控制:

锁机制:

参看 ↓ 数据库锁

MVCC:
  • MVCC可以使用 乐观(optimistic)锁悲观(pessimistic)锁来实现
  • 各数据库中都有对MVCC的实现 且实现方式都不相同
  • 应对高并发事务 MVCC比单纯的加锁更高效
  • InnoDB支持MVCC InnoDB存储引擎在数据库每行数据的后面添加了三个字段
  • MVCC只在 读已提交 READ COMMITTED可重复读 REPEATABLE READ 两个隔离级别下工作

隐藏字段:

posted @ 2023-07-25 17:39  熏晴微穗  阅读(31)  评论(0编辑  收藏  举报