MySQL的事务机制

事务

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

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 事务的特性。

相关推荐
遇见火星1 小时前
OpenEuler-22.03-LTS上利用Ansible轻松部署MySQL 5.7
mysql·ansible·openeuler
CL_IN2 小时前
高效集成销售订单数据到MySQL的方法
android·数据库·mysql
devlei2 小时前
Android JankStats实现解析
android
Vesper633 小时前
【Android】‘adb shell input text‘ 模拟器输入文本工具使用教程
android·adb
MyhEhud4 小时前
Kotlin apply 方法的用法和使用场景
android·kotlin·kotlin apply函数
元气满满的热码式4 小时前
MySQL启动报错解决
运维·数据库·mysql
猿小喵4 小时前
MySQL异常SQL排查
数据库·sql·mysql
ClouGence5 小时前
时序数据库 TDengine 到 MySQL 数据迁移同步
mysql·时序数据库·tdengine
多敲代码防脱发5 小时前
数据库MySQL原理(相关程序)
数据库·mysql