当前位置: 首页 > web >正文

java基础(十)sql的mvcc

一、事务特性与实现原理

1. ACID特性详解

特性说明实现机制生活案例
原子性事务操作要么全部成功,要么全部回滚Undo Log网购:支付成功则商品发货,支付失败则资金退回
一致性事务前后数据库保持完整性约束ACID共同保证转账:A账户-200、B账户+200后,总额保持不变
隔离性并发事务相互隔离,互不干扰MVCC/锁机制电影院售票:多个售票窗口同时卖票不会出售同一座位
持久性事务提交后数据永久存储,故障不丢失Redo Log银行存钱:柜台确认存款后,即使断电记录也不会丢失

2. 事务实现机制


  • Undo Log:记录数据修改前的状态,用于事务回滚

    -- 更新前记录旧值到Undo Log
    UPDATE users SET balance=800 WHERE id=1; 
    -- Undo Log: {id:1, balance:1000}

  • Redo Log:记录物理修改,确保故障恢复

    /* 修改流程:
    1. 内存更新Buffer Pool 
    2. 写Redo Log: "pageX offsetY更新为800"
    3. 后台刷脏页到磁盘 */

二、并发问题与解决方案

1. 三大并发问题

问题类型现象描述案例场景
脏读读取到未提交的临时数据财务系统看到未提交的工资调整,导致报表错误
不可重复读同事务内两次读取结果不一致机票查询:第一次看到余票3张,付款时提示余票0
幻读同条件查询返回的记录数不同统计在线用户:第一次10人,刷新后变成12人

2. 隔离级别对比

隔离级别脏读不可重复读幻读实现方式
读未提交(Read Uncommitted)直接读最新数据
读已提交(Read Committed)每次SELECT前生成Read View
可重复读(Repeatable Read)事务开始生成Read View
串行化(Serializable)读写锁阻塞访问

:MySQL默认隔离级别为可重复读,能解决幻读大部分场景

3. 幻读特殊场景示例

-- 事务A(YA33操作)
BEGIN;
SELECT * FROM orders WHERE amount>1000; -- 返回0条
​
-- 事务B插入并提交
INSERT INTO orders VALUES(5,2000,'B');
​
-- 事务A尝试更新"不存在"的数据
UPDATE orders SET user='YA33' WHERE amount>1000; -- 影响1行
SELECT * FROM orders WHERE amount>1000; -- 出现幻读!

解决方案:对关键操作使用锁定读

SELECT * FROM orders WHERE amount>1000 FOR UPDATE; -- 加Next-Key Lock

三、MVCC多版本并发控制

1. 核心组件

组件作用
Read View事务的数据快照
trx_id记录最后修改事务ID的隐藏列(当前的事务被那个id维护)
roll_pointer指向Undo Log旧版本链的指针(指向你的老数据)

2. Read View工作流程

首先read view 维护了四个关键的数据

  • 当前事务的id

  • 未提交事务id(维护很多已经开始未提交,安升序排序)

  • 未开始事务id

========================================================================

  • 当一个读取事务进来,与最小的活跃事务id进行比较,小就读,不小就继续

  • 然后与最大的事务id进行比较,大就不读,小就继续

  • 判断是否与本身的事务id相等,相等就读,不相等就继续

  • 判断是否在活跃事务列表里面,在就不读,不在就读

3. 不同隔离级别的Read View

  • 读已提交:每次SELECT生成新Read View

  • 可重复读:首次SELECT生成Read View,整个事务复用

四、锁机制深度剖析

1. 锁类型全景


2. 行锁冲突矩阵

X(排他锁)S(共享锁)
X锁冲突冲突
S锁冲突兼容

3. 锁优化实践

场景1:范围更新不阻塞

-- 事务A(YA33操作)
UPDATE users SET score=score+1 WHERE id<10; -- 锁(-∞,10)
​
-- 事务B
UPDATE users SET vip=1 WHERE id>15;        -- 锁(15,+∞) 不冲突

场景2:无索引全表锁

-- 无索引字段更新导致全表锁
UPDATE products SET status=0 WHERE name LIKE '%清仓%'; -- 慎用!

五、日志系统工作原理

1. 日志类型对比

日志类型层级作用关键特性
Redo Log存储引擎层故障恢复物理日志,顺序写
Undo Log存储引擎层事务回滚/MVCC逻辑日志,链式存储
BinlogServer层主从复制/数据恢复逻辑日志,三种格式
Relay LogServer层从库中转主库Binlog临时中转日志

2. Binlog三种格式

格式优点缺点适用场景
STATEMENT日志量小函数结果可能不一致简单SQL
ROW数据绝对一致日志量大数据安全要求高
MIXED自动选择最优模式切换策略复杂通用场景

3. 两阶段提交流程

崩溃恢复规则

  • 发现Prepare的Redo Log:检查Binlog

    • Binlog存在 → 提交事务

    • Binlog不存在 → 回滚事务

六、性能调优实战

1. EXPLAIN关键字段解读

EXPLAIN SELECT * FROM users WHERE name='YA33';
字段优化建议
typeref理想范围:const/ref/range
keyidx_name实际使用索引名
rows1扫描行数越少越好
ExtraUsing index出现Using filesort需优化

2. 常见优化方案

场景1:深分页优化

-- 低效写法
SELECT * FROM logs ORDER BY id LIMIT 1000000,10;
​
-- 高效写法(YA33操作)
SELECT * FROM logs WHERE id>1000000 ORDER BY id LIMIT 10;

场景2:索引失效避免

- SELECT * FROM users WHERE YEAR(create_time)=2023; -- 索引失效
+ SELECT * FROM users WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31';

3. 强制索引使用

-- 优化器选错索引时干预
SELECT /*+ INDEX(products idx_price) */ * 
FROM products FORCE INDEX(idx_price)
WHERE price BETWEEN 100 AND 500;

七、高可用架构

1. 主从复制流程

2. 分库分表策略

拆分方式特点适用场景
垂直分库按业务拆分(订单/用户)业务耦合度低
水平分库数据分片到不同服务器单库性能瓶颈
垂直分表大表拆小表(商品+商品详情)字段访问频率差异大
水平分表单表数据拆分(按用户ID取模)单表数据量超大

示例:订单表分片

-- 原始表
CREATE TABLE orders (id BIGINT, user_id INT, amount DECIMAL);
​
-- 分片后(YA33的user_id=12345)
INSERT INTO orders_5 (user_id,amount) VALUES (12345,99.9); 
-- 分片规则: user_id % 10 = 5 → orders_5

通过全面理解MySQL的事务机制、锁策略、日志系统及优化技巧,可构建高性能高可用的数据库架构。在实际应用中,需根据业务场景灵活选择隔离级别、锁机制和分片策略,如YA33在处理金融交易时应采用串行化隔离级别,而在用户日志分析场景可使用读已提交级别提升并发性能。

http://www.xdnf.cn/news/18193.html

相关文章:

  • 字节 Golang 大模型应用开发框架 Eino简介
  • 进程互斥的硬件实现方法
  • 私人AI搜索新突破:3步本地部署Dify+Ollama+QwQ,搜索能力MAX
  • 《动手学深度学习v2》学习笔记 | 1. 引言
  • Nacos 注册中心学习笔记
  • C++入门自学Day11-- String, Vector, List 复习
  • Kafka 面试题及详细答案100道(23-35)-- 核心机制2
  • 3D打印——给开发板做外壳
  • 最新技术论坛技术动态综述
  • XF 306-2025 阻燃耐火电线电缆检测
  • 【Linux | 网络】高级IO
  • JMeter(进阶篇)
  • (一)Python + 地球信息科学与技术 (GeoICT)=?
  • CentOS7安装部署GitLab社区版
  • 第3章 Java NIO核心详解
  • Portkey-AI gateway 的一次“假压缩头”翻车的完整排障记:由 httpx 解压异常引发的根因分析
  • java八股文-(spring cloud)微服务篇-参考回答
  • FreeRTOS在中断服务例程(ISR)中使用队列
  • 小白成长之路-k8s部署discuz论坛
  • Python爬虫-解决爬取政务网站的附件,找不到附件链接的问题
  • Blender模拟结构光3D Scanner(二)投影仪内参数匹配
  • scikit-learn/sklearn学习|多任务套索回归MultiTaskLasso解读
  • The Network Link Layer: 无线传感器中Delay Tolerant Networks – DTNs 延迟容忍网络
  • C++---迭代器删除元素避免索引混乱
  • 最长回文子串问题:Go语言实现及复杂度分析
  • Flink Stream API核心概念继承体系
  • 代码随想录刷题Day34
  • 分治-归并-315.计算右侧小于当前元素的个数-力扣(LeetCode)
  • 42 C++ STL模板库11-容器4-forward_list
  • macos 安装nodepad++ (教程+安装包+报错后的解决方法)