Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
  • SQL编程50题
  • 基础篇
  • 索引篇
  • 事务篇
    • 何为事务?
    • 事务四大特性
    • 并发事务带来的问题?
    • 事务隔离级别
    • 如何解决不可重复度?
    • InnoDB可重复读如何解决幻读?
    • ReadView在MVCC如何工作?
    • InnoDB可重复读可以完全解决幻读吗?
    • 临键锁是否可以防止删除操作导致的幻读?
  • 锁篇
  • 日志篇
  • 高可用篇
  • 分库分表
  • 性能优化
  • Mysql
Nreal
2023-11-15
目录

事务篇

# 何为事务?

事务分为:分布式事务,数据库事务;

数据库事务:多个对数据库的操作构成一个整体逻辑,要么全部执行,要不全不执行;

START TRANSACTION;
SQL1,SQL2;
COMMIT;
1
2
3

# 事务四大特性

ACID

A(原子性):事务是最小执行单位,要么全部完成,要么完全不起作用;

C(一致性):事务前后,数据一致;

I(隔离性):并发访问数据库,一个用户的事务不被其它事务干扰;

D(持久性):事务提交后,对数据库里的数据是持久的;

AID是手段,C是目的;

如何保证?

原子性通过 undo log 来保证;

隔离性通过 MVCC 或 锁机制 来保证;

持久性通过 redo log 来保证;

一致性通过 原子性+隔离性+持久性来保证;

# 并发事务带来的问题?

  • 脏读:一个事务读到 另一个未提交事务修改过的数据 ;

    A事务读取到B事务未提交修改的数据,B后续还有可能回滚,所以A读取到一个脏数据;

  • 不可重复读:同一个事务多次读取同一个数据,前后读到的数据不一致;

  • 幻读:同一个事务查询符合查询条件的 记录数量,前后查询数量不一致;

# 事务隔离级别

  • 读未提交:一个事务未提交,修改的数据被其它事务看见;
  • 读已提交:只有事务提交,修改的数据才能被其他事务看见;
  • 可重复读:事务启动后,所有数据是一致的;(InnoDB默认)
  • 串行化:对记录加锁,多个事务执行这条记录时,发生读写冲突,后访问事务必须等前一个事务执行完成;

隔离级别如何实现?

读未提交:读取最新数据;

读已提交:在每条语句执行前,生成ReadView;

可重复读:启动事务时,生成ReadView,整个事务期间,都是用这个ReadView;

串行化:读写锁;

# 如何解决不可重复度?

  1. 设置事务隔离级别;
  2. 行级锁:select...for update语句防止其他事务修改数据;
  3. 乐观锁:读取数据之后,执行写操作之前,再次检查数据是否被其他事务修改;

# InnoDB可重复读如何解决幻读?

  • 快照读,通过MVCC解决了幻读;

    可重复读下,开启事务后,在执行第一个查询语句后,会创建一个Read View,后续的查询语句会利用这个Read View,通过这个Read View可以在undo log版本连找到事务开始时的数据,所以事务过程中每次查询的数据都是一样的,即使中途有其他事务插入了新纪录,是查询不出来这条数据;

  • 当前读,通过临键锁解决了幻读;

    其他事务在临键锁范围内插入一条记录,这个插入语句被阻塞;

# ReadView在MVCC如何工作?

ReadView 4个重要字段:

  1. creator_trx_id :创建该 Read View 的事务的事务 id;
  2. m_ids : 在创建 Read View 时,当前数据库中「活跃事务」的事务 id 列表;
  3. min_trx_id :在创建 Read View 时,当前数据库中「活跃事务」中事务 id 最小的事务,也就是 m_ids 的最小值;
  4. max_trx_id :全局事务中最大的事务 id 值 + 1;

聚簇索引记录隐藏列:

  1. trx_id:当前事务的事务id;
  2. roll_pointer:指向undo版本链的指针;

创建Read View后,记录中trx_id的三种情况:

img

  • 如果记录的 trx_id 值小于 Read View 中的 min_trx_id 值,表示这个版本的记录是在创建 Read View 前已经提交的事务生成的,所以该版本的记录对当前事务可见;
  • 如果记录的 trx_id 值大于等于 Read View 中的 max_trx_id 值,表示这个版本的记录是在创建 Read View 后才启动的事务生成的,所以该版本的记录对当前事务不可见;
  • 如果记录的 trx_id 值在 Read View 的 min_trx_id 和 max_trx_id 之间,需要判断 trx_id 是否在 m_ids 列表中:
    1. 如果记录的 trx_id 在 m_ids 列表中,表示生成该版本记录的活跃事务依然活跃着(还没提交事务),所以该版本的记录对当前事务不可见;
    2. 如果记录的 trx_id 不在 m_ids列表中,表示生成该版本记录的活跃事务已经被提交,所以该版本的记录对当前事务可见;

# InnoDB可重复读可以完全解决幻读吗?

先快照读 后当前读;

  • T1 时刻:事务 A 先执行「快照读语句」:select * from t_test where id > 100 得到了 3 条记录。
  • T2 时刻:事务 B 往插入一个 id= 200 的记录并提交;
  • T3 时刻:事务 A 再执行「当前读语句」 select * from t_test where id > 100 for update 就会得到 4 条记录,此时也发生了幻读现象。

在开启事务之后,马上执行 select ... for update 这类当前读的语句,因为它会对记录加 next-key lock,从而避免其他事务插入一条新记录;

# 临键锁是否可以防止删除操作导致的幻读?

可以,删除语句陷入等待状态;

索引篇
锁篇

← 索引篇 锁篇→

Theme by Vdoing | Copyright © 2021-2024
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式