MySQL的事务机制

发布于:2025-03-16 ⋅ 阅读:(14) ⋅ 点赞:(0)

事务

事务概念:事务是一个完整的操作单元,不可分割,事务中的操作要么全部成功,要么全部失败。

1. 事务特性


ACID

1.1 原子性(A)

一个事务中所有操作是不能被分割的,要么所有的操作都成功,要么都失败

1.2 一致性(C)

事务开始前到事务结束后,数据总量保持不变的

  • 示例

    • 转账

      jack 钱数 kucy 钱数 总钱数
      开始前 jack:200 lucy:200 400
      结束后 jack:100 lucy:300 400
    • 买书

      书本数量 单价 存款
      开始前 2 100 300
      结束后 1 100 200

1.3 隔离性(I)

两个不同的事务之间是隔离的,互不影响

1.4 持久性(D)

事务一旦提交,数据永久保存磁盘上

2. 隔离级别【不同隔离级别产生的问题】

2.1 读未提交

read uncommitted

会出现脏读、幻读、不可重复读。

脏读:一个事务读到了另一个事务没有提交的数据

例如:A 欠 B 300元

还钱流程:

  1. A、B 开启事务
  2. B 查询余额,1000
  3. A 开始向 B 转账,A 打电话给 B,说我把钱转给你了,你看看
  4. B 再查询余额,1300,跟 A 说,是的,我收到了
  5. A 执行了 rollback
  6. B 再查余额,1000,因为 A 回滚了操作

2.2 读已提交

read committed :oracle 默认

只解决了脏读,会出现幻读及不可重复读。

不可重复读:在同一个事务中,连续两次读取到的数据不一致

2.3 可重复读

repeatable read :mysql 默认

只会出现幻读(对于增加)

  • A 事务执行查询,查到 3 条数据

  • B 事务插入一条数据,并提交

  • A 事务执行了更新,发现更新的数量是 4 条,感觉像出现了幻觉

幻读处理:可重复读隔离级别在一定程度上解决了幻读问题,但并非完全避免。它主要通过以下机制来减少幻读的可能性:

  1. 快照读:对于普通的 SELECT 查询,MySQL 使用多版本并发控制(MVCC)来提供一个数据的一致性快照。事务在执行第一个查询操作时会创建一个一致性视图(Read View),之后的查询都会基于这个视图进行。这意味着即使其他事务在此期间插入了新记录,当前事务也无法看到这些新记录,从而避免了幻读(在大多数情况下)。
  2. 当前读:对于需要修改数据的操作(如 INSERT、UPDATE、DELETE)或使用锁定读(如 SELECT … FOR UPDATE),MySQL 使用 Next-Key Locking 机制。这是一种特殊的锁,它包括了记录锁和间隙锁,可以防止其他事务在已锁定的记录附近插入新记录,从而进一步减少幻读的可能性。
  3. 然而,即使在可重复读隔离级别下,幻读在某些特定场景下仍然可能发生。例如,当事务在更新记录时改变了记录的隐藏 trx_id 值,或者其他事务在间隙锁的范围内插入了新记录时,就可能出现幻读。

2.4 串行化

Serializable

不会有任何问题。相当于锁表,效率极低

2.5 实际开发会用到的隔离级别

  1. read committed :oracle默认

    缺点:不可重复读

  2. repeatable read :mysql 默认

扩展:read committed 已经可以解决大部分问题,为什么 MySQL 的默认隔离级别还会设置成 repeatable read

  1. 可重复读
  2. SELECT @@transaction_isolation;

3. MVCC

MVCC 是数据库中一种保证并发性与数据安全性的思想

3.1 生效时间

只有在数据事务隔离级别是读已提交或者可重复读时生效

  1. 读是从缓存中拿数据
    • 第一次查询时,查询表,获取数据,写入数据库缓存
    • 后期的查询,只要是缓存中有的数据,直接查缓存,不查询表。以此来保证并发性
  2. 写的时候会把数据库把最新的数据同步到缓存
    • 保证安全性

3.2 使用三种日志

  1. Undolog 日志:在执行更新语句之前,需要先将旧的数据拷贝到 Undo Log 中。Undo 日志在事务提交或回滚的时候用于还原数据。
  2. Redo 日志:当事务提交时,MySQL 会将事务修改写入到 Redo Log 中。如果 MySQL 突然崩溃并且缓存数据不能恢复,Redo 日志就可以帮助 MySQL 恢复数据。
  3. Binlog 日志:Binlog 日志主要用于主从复制。当从库需要和主库数据保持一致时,需要从主库中读取 Binlog 的数据进行同步。

在执行插入、更新和删除操作时,MySQL 需要进行两个操作。第一个操作是将旧数据的快照保存到 Undolog 日志中。第二个操作是将新的数据记录到 InnoDB 表空间中,并同时将新数据的变更写入到 Redolog 日志和 Binlog 日志中。当事务提交时,MySQL 只有收到了所有三种类型的日志都写入成功的信号,才会返回成功事务提交的响应。这就实现了 MySQL 的 ACID 事务的特性。