MySQL 事务 ACID

MySQL 事务 ACID


MySQL 事务的 ACID

一、ACID 是什么

特性 英文 含义
A Atomicity 原子性
C Consistency 一致性
I Isolation 隔离性
D Durability 持久性

二、Redo Log 和 Undo Log

日志 类型 作用
Redo Log 物理日志 保证持久性
Undo Log 逻辑日志 保证原子性 + MVCC

三、Redo Log

核心思想

使用:

  • WAL(Write Ahead Log)

原则:

  • 先写日志
  • 再写磁盘

四、Undo Log

作用:

  • 回滚事务
  • MVCC 多版本控制

Redo Log 刷盘策略


innodb_flush_log_at_trx_commit

配置值 刷盘策略 安全性 性能
1 每次提交立即刷盘 最高 最低
0 每秒刷盘 最低 最高
2 每次提交写 OS Cache 折中 折中

面试回答

  • 1 最安全
  • 0 性能最好
  • 2 是平衡方案

生产环境:

  • 一般使用 1

MySQL 隔离级别


MySQL 四种隔离级别

隔离级别 英文 问题
读未提交 Read Uncommitted 会脏读
读已提交 Read Committed 会不可重复读
可重复读 Repeatable Read 默认级别
串行化 Serializable 性能最差

MySQL 默认隔离级别

text 复制代码
Repeatable Read

即:

  • 可重复读

脏读、不可重复读、幻读


一、脏读

定义:

  • 读到未提交数据

二、不可重复读

定义:

  • 两次查询结果不同

原因:

  • 中间被其他事务修改

三、幻读

定义:

  • 两次查询记录数量不同

原因:

  • 中间有插入/删除

幻读解决方案


InnoDB 如何解决幻读

一、快照读

使用:

  • MVCC

看到:

  • 历史快照

二、当前读

使用:

  • 间隙锁(Gap Lock)

作用:

  • 锁定范围
  • 防止插入

三、总结

InnoDB:

  • MVCC + 间隙锁

解决:

  • 幻读问题

四、补充

串行化级别:

  • 也能解决幻读

缺点:

  • 性能差

MVCC


MVCC 原理

一、核心思想

MVCC:

text 复制代码
Multi-Version Concurrency Control

即:

  • 多版本并发控制

二、Read View 可见性规则

可见

  • 小于最小活跃事务 ID
  • 已提交事务

不可见

  • 活跃事务列表中的事务
  • 大于当前事务 ID

三、简单理解

可见:

  • 当前事务开始前已经提交的数据

不可见:

  • 未提交数据
  • 未来事务数据

悲观锁 vs 乐观锁


一、悲观锁

核心思想

认为:

  • 一定会发生冲突

所以:

  • 先加锁
  • 再操作

典型实现

Java

  • synchronized
  • ReentrantLock

MySQL

sql 复制代码
SELECT ... FOR UPDATE

优缺点

优点

  • 强一致性

缺点

  • 性能差
  • 可能死锁

二、乐观锁

核心思想

认为:

  • 冲突概率低

所以:

  • 不加锁
  • 更新时检查版本

典型实现

  • CAS
  • 版本号机制

优缺点

优点

  • 高并发
  • 无死锁

缺点

  • 冲突多时大量重试

三、选择原则

场景 推荐方案
写多读少 悲观锁
读多写少 乐观锁

实际案例

场景 方案
库存扣减 悲观锁
用户信息更新 乐观锁

GC 问题排查


GC 导致接口超时排查

第一步:确认是否是 GC

观察:

  • 接口超时是否周期性
  • CPU 是否飙升
  • 是否频繁 GC

第二步:查看 GC 情况

命令:

bash 复制代码
jstat -gc

重点:

  • Full GC 次数
  • Full GC 耗时

第三步:分析 GC 日志

排查:

  • 内存不足
  • System.gc()
  • 元空间溢出

第四步:分析内存泄漏

生成 dump:

bash 复制代码
jmap

分析工具:

  • MAT

查看:

  • 哪些对象占用内存最多

第五步:定位代码问题

常见问题:

  • ThreadLocal 未清理
  • 无界缓存
  • 大对象频繁创建

常见优化方案

  • 调整堆内存
  • 优化 GC 参数
  • 修复内存泄漏
  • 提前预热

TCP 三次握手


TCP 三次握手流程

第一次

客户端发送:

text 复制代码
SYN

作用:

  • 请求建立连接
  • 发送初始序列号

第二次

服务端回复:

text 复制代码
SYN + ACK

作用:

  • 确认客户端请求
  • 发送自己的序列号

第三次

客户端发送:

text 复制代码
ACK

作用:

  • 确认收到服务端响应

三次握手作用

一、同步序列号

保证:

  • 后续数据有序传输

二、防止历史连接

避免:

  • 旧 SYN 导致资源浪费

为什么不能两次握手

问题:

  • 服务端无法确认客户端是否收到 ACK

结果:

  • 可能建立无效连接

TCP 四次挥手


TCP 四次挥手流程

第一次

客户端发送:

text 复制代码
FIN

表示:

  • 不再发送数据

第二次

服务端回复:

text 复制代码
ACK

表示:

  • 收到关闭请求

第三次

服务端发送:

text 复制代码
FIN

表示:

  • 数据发送完成

第四次

客户端回复:

text 复制代码
ACK

然后进入:

text 复制代码
TIME_WAIT

为什么是四次挥手

原因:

  • TCP 是全双工

特点:

  • 两个方向独立关闭

为什么不能三次

因为:

  • 服务端收到 FIN 时
  • 可能还有数据没发送完

所以:

  • ACK 和 FIN 不能合并

TIME_WAIT


TIME_WAIT 作用

一、保证最后 ACK 到达

如果 ACK 丢失:

  • 服务端会重发 FIN

客户端必须还能响应。


二、防止旧报文影响新连接

等待:

text 复制代码
2MSL

保证:

  • 网络中的旧报文全部消失

为什么等待 2MSL

第一原因

确保:

  • 服务端能收到最后 ACK

第二原因

防止:

  • 延迟报文污染新连接

数据量扩大 1000 倍


数据量暴增后的优化

一、数据库

核心方案

  • 分库分表
  • 读写分离

二、拆分方式

垂直拆分

按业务拆:

  • 用户库
  • 订单库

水平拆分

按:

text 复制代码
userId

进行分片。


三、缓存优化

Redis Cluster

作用:

  • 数据分片

多级缓存

架构:

text 复制代码
Caffeine → Redis → MySQL

四、应用层

水平扩容

使用:

  • K8s
  • HPA 自动伸缩

GC 优化

方案:

  • 减少对象创建
  • 提前处理大对象

五、消息队列

优化:

  • 增加分区
  • 增加消费者

避免:

  • 消息积压

六、架构演进步骤

阶段 方案
第一阶段 SQL 优化 + 垂直扩容
第二阶段 读写分离 + 缓存
第三阶段 分库分表
第四阶段 微服务 + 异步化

2 亿数据查询优化


2 亿数据为什么还能查得快

一、核心原因

B+Tree 索引

特点:

  • 高度低
  • 查询磁盘 IO 少

二、InnoDB 理论能力

支持:

text 复制代码
16 亿

级数据。

索引查询:

  • 只需 3~4 次磁盘 IO

三、常见问题

1)深度分页

错误方案:

sql 复制代码
LIMIT 1000000, 20

优化方案

使用:

sql 复制代码
WHERE id > last_id

即:

  • 游标分页

2)回表过多

问题:

  • 先查索引
  • 再查数据页

解决方案

使用:

  • 覆盖索引

3)COUNT 慢

解决:

  • 汇总表
  • 从库统计

4)索引维护成本高

经验:

  • 超过 5000 万建议分表

四、分表建议

推荐数量

text 复制代码
64 ~ 128

张表。


每张表数据量

text 复制代码
150万 ~ 300万

最佳。


五、复杂查询优化

方案:

  • Elasticsearch
  • ClickHouse

六、生产经验

优化后:

  • 简单查询几十毫秒

长期方案:

  • 分表更稳妥
相关推荐
长栎1 小时前
写 for 循环写了十年,你却从没用过迭代器模式最狠的那一面
后端
LiaCode1 小时前
Redis 在生产项目的使用
前端·后端
用户559822481221 小时前
Docker Compose Down 导致容器数据误删——ext4 日志恢复全记录
后端
LiaCode1 小时前
一天学完 redis 的爽翻版核心知识总结
前端·后端
大刚测试开发实战1 小时前
如何内网穿透访问本地私有化部署的TestHub
前端·后端·github
xiaodaoluanzha1 小时前
迄今為止,最簡單的編程語言 Nolang
前端·后端
Csvn1 小时前
Docker 容器管理入门 — 从镜像到容器编排
后端
用户762352425911 小时前
ShardingJDBC
后端
行者全栈架构师1 小时前
IDEA 中 Maven 项目的 15 个红色报错快速解决方法
java·后端
Colin草率地做慢慢地改1 小时前
关于QuickStore这个项目的重构(2)- 数据库建表文件
后端·面试·架构