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

数据库基础——事务隔离级别

数据库基础——事务隔离级别

事务隔离级别是数据库系统中非常重要的概念,它决定了事务之间如何相互"看到"对方的数据变化。我将用更通俗易懂的方式解释这四种隔离级别,特别是你感到困惑的"读已提交"和"可重复读"级别。

一、四种隔离级别概述

我们可以把隔离级别想象成教室之间的隔墙厚度:

隔离级别隔墙厚度问题解决存在问题
读未提交透明玻璃脏读
读已提交薄墙解决脏读不可重复读
可重复读厚墙解决脏读、不可重复读幻读
串行化实心墙解决所有问题性能差

二、各级别详细解释

1. 读未提交(Read Uncommitted) - 透明玻璃

特点:事务可以读取其他事务未提交的修改。

问题

  • 脏读(Dirty Read):读到别人还没确认的数据,如果对方回滚,你读到的就是"脏数据"。

示例

-- 事务A
UPDATE accounts SET balance = balance - 100 WHERE id = 1; -- 未提交-- 事务B(读未提交隔离级别)
SELECT balance FROM accounts WHERE id = 1; -- 能看到A未提交的修改

2. 读已提交(Read Committed) - 薄墙

特点:只能读取已提交的数据。

解决了:脏读问题。

新问题

  • 不可重复读(Non-repeatable Read):在同一事务中,两次读取同一数据可能结果不同。

示例

-- 事务A第一次查询
SELECT balance FROM accounts WHERE id = 1; -- 返回1000-- 事务B提交了修改
UPDATE accounts SET balance = 900 WHERE id = 1;
COMMIT;-- 事务A第二次查询(同一事务内)
SELECT balance FROM accounts WHERE id = 1; -- 返回900(与第一次不同)

现实比喻:你在看一本书,别人可以在你阅读过程中修改书的内容,你每次翻页可能看到不同的内容。

3. 可重复读(Repeatable Read) - 厚墙

特点:事务开始时建立"快照",整个事务期间都读取这个快照。

解决了:脏读和不可重复读问题。

新问题

  • 幻读(Phantom Read):虽然同一数据不会变,但可能出现新数据行。

示例

-- 事务A开始
SELECT COUNT(*) FROM accounts WHERE type = 'saving'; -- 返回5-- 事务B插入并提交
INSERT INTO accounts(id, type, balance) VALUES(11, 'saving', 500);
COMMIT;-- 事务A再次查询
SELECT COUNT(*) FROM accounts WHERE type = 'saving'; -- 仍返回5(可重复读)-- 但事务A执行更新时会发现影响行数超出预期
UPDATE accounts SET balance = balance + 10 WHERE type = 'saving';
-- 可能影响6行而不是预期的5行

现实比喻:你在看一本书的拍照快照,书的内容实际可能已经变化,但你看到的始终是拍照时的内容。不过如果有人往书里夹新页,你可能会发现。

4. 串行化(Serializable) - 实心墙

特点:完全隔离,事务串行执行。

解决了:所有问题(脏读、不可重复读、幻读)。

代价:性能最低,并发性差。

三、重点对比:读已提交 vs 可重复读

读已提交(Read Committed)

  • 数据真实性:总是读取最新已提交的数据
  • 问题:同一事务内多次读取同一数据可能结果不同
  • 适用场景:需要实时数据的系统(如银行ATM机查询余额)

可重复读(Repeatable Read)

  • 数据一致性:事务开始时建立数据快照,整个事务期间读取相同数据
  • 问题:可能读到"过期"数据,存在幻读
  • 适用场景:需要数据一致性的报表生成、统计分析

四、如何选择隔离级别

  1. 优先考虑可重复读:MySQL默认级别,平衡了性能和数据一致性
  2. 需要高实时性:考虑读已提交(Oracle默认)
  3. 严格要求数据一致性:考虑串行化(但性能影响大)
  4. 几乎不使用:读未提交(仅用于特殊场景)

五、实际案例分析

银行转账场景

-- 使用可重复读隔离级别
START TRANSACTION;-- 检查账户A余额(假设返回1000)
SELECT balance FROM accounts WHERE id = 1;-- 在此期间,另一个事务从账户A转出100并提交
-- 但当前事务仍看到余额为1000-- 尝试转出800
UPDATE accounts SET balance = balance - 800 WHERE id = 1;
-- 实际会检查真实余额,如果不足会失败,防止透支
http://www.dtcms.com/a/265379.html

相关文章:

  • 热血三国建筑攻略表格
  • Dubbo RPC 序列化问题记录
  • 信号与槽(1)
  • JXLS 库导出复杂 Excel
  • 多模态AI Agent技术栈解析:视觉-语言-决策融合的算法原理与实践
  • MySQL 8.0 OCP 1Z0-908 题目解析(18)
  • 如何摆脱情绪的自动驾驶模式:掌控你的内心反应
  • 如何将信息从 iPhone 同步到Mac(完整步骤和示意图)
  • 网络工具如何帮助消除网络安全风险
  • 解决RHEL/Rocky Linux 虚拟化KVM添加 物理主机异常
  • Python Rich 详解:让终端输出焕发新生
  • 一、Docker:一场颠覆应用部署与运维的容器革命
  • C# Linq to SQL:数据库编程的解决方案
  • YOLOv8 模型转换 ONNX 后 C# 调用异常:一个参数引发的跨平台适配难题
  • van-tabbar-item选中active数据变了,图标没变
  • Rust与Locust集成实战
  • 制作一款打飞机游戏76:分数显示
  • 【第三章:神经网络原理详解与Pytorch入门】01.神经网络算法理论详解与实践-(2)神经网络整体结构
  • Codeforces Round 1034 (Div. 3)
  • 互联网大厂Java面试实录:Spring Boot与微服务在电商场景中的应用
  • SerialAssist 串口调试助手 - 功能介绍
  • 解决 Spring Boot 对 Elasticsearch 字段没有小驼峰映射的问题
  • io-进程/线程--理论+实操
  • 旋量理论与运动旋量计算:Sympy中的数学实现与物理内涵
  • 实验室超算替代方案:AMD EPYC 双路高性能工作站,预装全套科研软件 配置科研环境3天拿到全套已优化工作站
  • leetcode 3304. 找出第 K 个字符 I 简单
  • 【Java工程师面试全攻略】Day10:系统性能优化全链路实践
  • AI时代SEO关键词策略
  • 异步Websocket构建聊天室
  • mac init tailwind css 配置文件报错