银行转账惊魂记:MySQL事务与隔离级别的奇幻冒险 - 详解

news/2025/11/6 16:37:42/文章来源:https://www.cnblogs.com/yxysuanfa/p/19196991

从一个看似简单的银行转账,揭开数据库事务的神秘面纱

引子:午夜的银行危机

在数字金融城,有一家名为"数据银行"的金融机构。这里的柜员小王正在处理一天的最后一笔业务。

-- 小王要执行转账操作
UPDATE accounts SET balance = balance - 1000 WHERE account_id = 'A';
UPDATE accounts SET balance = balance + 1000 WHERE account_id = 'B';

就在小王执行完第一条SQL,准备执行第二条时——啪!停电了!

第一章:事务的诞生 - 要么全有,要么全无

1.1 灾难的后果

第二天恢复供电后,银行发现了可怕的事情:

  • 账户A:被扣了1000元

  • 账户B:没有收到1000元

  • 1000元:消失在数字空间中!

客户A怒气冲冲地来找小王:"我的钱呢?!"

1.2 拯救者出现

正在这时,数据库专家老李出现了。他微笑着说:

"这个问题很好解决,我们需要使用事务!"

老李重新设计了转账流程:

START TRANSACTION;  -- 开始事务
UPDATE accounts SET balance = balance - 1000 WHERE account_id = 'A';
UPDATE accounts SET balance = balance + 1000 WHERE account_id = 'B';
COMMIT;  -- 提交事务

老李解释道

"事务就像是一个保护罩:

  • 开始事务:开启保护模式

  • 执行操作:在保护罩内操作

  • 提交事务:确认所有操作成功

  • 如果中途失败:回滚所有操作"

1.3 ACID四骑士

老李继续解释,事务有四个守护骑士:

class TransactionACID:def explain(self):return {"A(原子性)": "要么全部成功,要么全部失败,没有中间状态","C(一致性)": "事务前后,数据库保持一致性规则","I(隔离性)": "多个事务相互隔离,互不干扰","D(持久性)": "事务提交后,修改永久保存"}

小王恍然大悟:"就像转账,要么成功,要么失败,绝不会出现钱消失的情况!"

第二章:并发世界的混乱

2.1 新的挑战

随着业务发展,数据银行需要同时处理多个客户请求。很快,新的问题出现了...

场景一:脏读的尴尬

早上9点,客户A和客户B同时来办业务:

-- 事务1(小王):调整利率
START TRANSACTION;
UPDATE accounts SET interest_rate = 0.05;  -- 改为5%
-- 还没提交!
-- 事务2(小张):查询利率
START TRANSACTION;
SELECT interest_rate FROM accounts;  -- 读到了5%!

问题:小张读到了小王未提交的数据!如果小王回滚事务,小张就看到了"脏数据"。

场景二:不可重复读的困惑
-- 事务1(小王):查询余额
START TRANSACTION;
SELECT balance FROM accounts WHERE account_id = 'A';  -- 第一次查询:1000元
-- 事务2(小张):转账入账
START TRANSACTION;
UPDATE accounts SET balance = balance + 500 WHERE account_id = 'A';
COMMIT;
-- 事务1(小王):再次查询
SELECT balance FROM accounts WHERE account_id = 'A';  -- 变成1500元!

小王困惑:"同一个事务中,两次查询结果不一样?这太奇怪了!"

场景三:幻读的神秘事件
-- 事务1(小王):统计VIP客户数量
START TRANSACTION;
SELECT COUNT(*) FROM customers WHERE level = 'VIP';  -- 结果:100人
-- 事务2(小张):新增VIP客户
START TRANSACTION;
INSERT INTO customers VALUES (... , 'VIP');
COMMIT;
-- 事务1(小王):再次统计
SELECT COUNT(*) FROM customers WHERE level = 'VIP';  -- 结果:101人!

小王惊呆了:"客户数量自己增加了?难道见鬼了?"

第三章:隔离级别的守护结界

3.1 老李的解决方案

面对这些混乱,老李搬出了四大"隔离级别结界":

-- MySQL的四种隔离级别
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;    -- 读未提交
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;      -- 读已提交
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;     -- 可重复读
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;        -- 串行化

3.2 结界效果演示

老李用生动的比喻解释每个隔离级别:

级别1:读未提交(Read Uncommitted)

"就像在开放式办公室工作,你能听到隔壁同事还没确定的方案"

-- 什么都能看到,包括别人未提交的数据
-- 可能遇到:脏读、不可重复读、幻读
级别2:读已提交(Read Committed)

"就像在标准办公室,只能听到同事正式宣布的消息"

-- 只能看到已提交的数据
-- 避免脏读,但可能遇到不可重复读、幻读
级别3:可重复读(Repeatable Read)

"就像在私人办公室,你开始工作时的数据快照保持不变"

-- MySQL默认级别!
-- 避免脏读、不可重复读,可能遇到幻读
级别4:串行化(Serializable)

"就像独享整个办公室,一次只能一个人工作"

-- 完全隔离,避免所有问题,但性能最低

3.3 隔离级别对照表

老李画了一张魔法卷轴:

隔离级别脏读不可重复读幻读性能
读未提交❌ 可能❌ 可能❌ 可能⭐⭐⭐⭐⭐
读已提交✅ 避免❌ 可能❌ 可能⭐⭐⭐⭐
可重复读✅ 避免✅ 避免❌ 可能⭐⭐⭐
串行化✅ 避免✅ 避免✅ 避免

小王思考:"原来MySQL默认用'可重复读',是在性能和一致性之间找到了平衡!"

第四章:MVCC的多版本时空魔法

4.1 老李的时空理论

小王还是不明白:"可重复读是怎么实现的?难道数据库有时光机?"

老李神秘一笑:"没错,就是MVCC(多版本并发控制)时光机!"

4.2 MVCC的工作原理

老李用故事解释:

"想象每个事务都有自己的时间线。当事务开始时,数据库为它创建一个数据快照。在这个事务的生命周期内,它看到的都是这个快照版本的数据。"

# 简化的MVCC概念
class MVCCMagic:def __init__(self):self.versions = {}  # 存储数据的不同版本self.trx_id = 0     # 事务IDdef create_snapshot(self, trx_id):"""为事务创建数据快照"""snapshot = {}for key, value in self.versions.items():# 只包含对该事务可见的版本if self.is_visible(trx_id, value):snapshot[key] = valuereturn snapshot

4.3 版本链的魔法

老李继续画图解释:

账户A的余额版本链:
版本3: 余额2000 (事务103修改,已提交) ← 当前最新版本
版本2: 余额1500 (事务102修改,已提交)  
版本1: 余额1000 (事务101修改,已提交)

当事务104开始时:

  • 它看到的是版本3(2000元)

  • 即使事务105修改了余额,事务104仍然看到版本3

  • 这就实现了"可重复读"!

第五章:锁机制的守卫军团

5.1 共享锁与排他锁

老李又介绍了另一支守护力量——锁军团

class LockArmy:def lock_types(self):return {"共享锁(S锁)": "多个事务可以同时读,但不能写","排他锁(X锁)": "一个事务独占,其他事务不能读也不能写"}

5.2 锁的兼容性

老李用会议室预约来比喻:

共享锁(S锁):像研讨会,可以多人同时参加
排他锁(X锁):像私人会议,一次只能一个人用

锁兼容表:
      | S锁  | X锁
------|------|------
S锁   | ✅   | ❌
X锁   | ❌   | ❌

5.3 行锁、表锁、间隙锁

老李继续介绍锁军团的兵种:

class LockSoldiers:def types(self):return {"行锁": "锁定单行数据,粒度小,并发高","表锁": "锁定整张表,粒度大,并发低","间隙锁": "锁定一个范围,防止幻读","临键锁": "行锁+间隙锁,MySQL的防幻读利器"}

第六章:实战演练 - 银行系统的事务设计

6.1 转账业务的完美解决方案

小王学以致用,重新设计转账系统:

-- 设置合适的隔离级别
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
-- 关键:先锁定相关行
SELECT balance FROM accounts WHERE account_id = 'A' FOR UPDATE;
SELECT balance FROM accounts WHERE account_id = 'B' FOR UPDATE;
-- 检查余额是否足够
IF (SELECT balance FROM accounts WHERE account_id = 'A') >= 1000 THENUPDATE accounts SET balance = balance - 1000 WHERE account_id = 'A';UPDATE accounts SET balance = balance + 1000 WHERE account_id = 'B';COMMIT;
ELSEROLLBACK;RAISE_ERROR '余额不足';
END IF;

6.2 死锁的预防与处理

老李提醒:"小心死锁!就像两个人在窄桥相遇,都不肯让路。"

-- 死锁场景
事务1: 锁定了A账户,等待锁定B账户
事务2: 锁定了B账户,等待锁定A账户
-- 互相等待,形成死锁!

解决方案

  1. 按固定顺序获取锁(先A后B)

  2. 设置锁等待超时

  3. 死锁检测与自动回滚

6.3 事务的最佳实践

老李总结出事务使用的黄金法则:

class TransactionBestPractice:def rules(self):return {"事务要短小": "长时间事务会锁定资源","避免交互操作": "事务中不要等待用户输入","处理好异常": "确保异常时正确回滚","选择合适的隔离级别": "不是越高越好","注意锁的粒度": "尽量使用行锁而非表锁"}

第七章:高级特性 - 保存点的时光标记

7.1 保存点的魔法

老李教给小王一个高级技巧:

START TRANSACTION;
UPDATE accounts SET balance = balance - 1000 WHERE account_id = 'A';
SAVEPOINT after_deduct;  -- 设置保存点
UPDATE accounts SET balance = balance + 1000 WHERE account_id = 'B';
-- 如果B账户异常,可以回滚到保存点
IF check_b_account_error() THENROLLBACK TO SAVEPOINT after_deduct;  -- 回滚到扣款后-- 处理异常逻辑...
END IF;
COMMIT;

小王惊叹:"这就像游戏存档!可以回到某个检查点重新开始!"

尾声:成为事务大师

经过老李的指导,小王成为了数据银行的首席事务专家。他总结了自己的学习心得:

"事务就像人生的选择:

  • 原子性:要么全心投入,要么彻底放弃

  • 一致性:始终保持内心的原则

  • 隔离性:专注自己的目标,不受外界干扰

  • 持久性:做出的承诺,就要坚持到底"

现在,数据银行的系统再也没有出现过数据不一致的问题。每当新员工入职,小王都会给他们讲那个"午夜转账惊魂"的故事...


通过这个生动的银行故事,我们深入理解了MySQL事务和隔离级别。记住:事务不是越隔离越好,而是在数据一致性和系统性能之间找到最佳平衡。理解原理,合理设计,你也能成为事务处理的大师!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/957883.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年深圳拼箱利比亚物流公司权威推荐榜单:大件运输利比亚物流/铁路利比亚物流/利比亚物流源头公司精选

在深圳这座全球贸易枢纽城市,选择一家专业的利比亚拼箱物流服务商,意味着您的货物将更有可能在复杂的国际贸易环境中安全高效抵达目的地。 随着中国与北非贸易往来日益密切,利比亚物流市场呈现出稳定增长态势,其中…

量化选股与量化交易第857篇:通达信金妖舞龙 - Leone

通达信金妖舞龙主图AFL18H := WMA(SMA(HHV(HIGH,18),9/2,1),3); DXS18L := WMA(SMA(LLV(LOW,18),9/2,1),3); 章鱼1 := (AFL18H+DXS18L)/2; C1:=C/REF(C,1)>1.095 AND H=C; C2:=AMOUNT< 550000000; DRAWBAND(AFL1…

2025年外墙柔性腻子粉厂家权威推荐:腻子粉/外墙腻子粉/内墙腻子粉源头生产厂家精选

外墙柔性腻子粉作为建筑外墙装饰与保护的关键材料,凭借其优异的柔韧性、卓越的抗裂性能和持久的耐候特性,在住宅、商业建筑、公共设施等外墙工程中发挥着不可或缺的作用。本文将基于建材行业技术标准与发展趋势,为您…

解决Could not create task …this and base files have different roots

直接编译运行Flutter项目是没问题的,但是单独打开Android项目进行编译却报错了。Multiple build operations failed. Could not create task :file_selector_android:generateDebugUnitTestConfig. Could not create …

【IEEE出版 | EI检索稳定、速度快 | 连续四届稳定检索】2025年第五届数字化社会与智能系统国际学术会议(DSInS 2025)

第五届数字化社会与智能系统国际学术会议将于2025年11月07-09日在海南海口-海南大学国际学术交流中心酒店举行。【EI检索稳定、速度快:IEEE出版,提交至IEEE Xplore、EI、Scopus、谷歌学术四个数据库检索;连续四届稳…

2025 年不锈钢护栏厂家最新推荐排行榜:涵盖防撞、桥梁、铝合金、河道等多类型,精选耐腐蚀美观耐用优质品牌

引言 随着基础设施建设与房地产行业的发展,不锈钢护栏市场需求日益增长,但行业乱象却让消费者选购时举步维艰。部分企业用劣质材质以次充好,导致护栏短时间内生锈损坏;有的企业服务断层,设计安装不规范,存在安全…

使用gdb调试core文件

本文分享自天翼云开发者社区《使用gdb调试core文件》.作者:小谢不用谢 GDB(GNU Debugger)是一个功能强大的调试工具,它可以用来调试C、C++、Objective-C等多种语言编写的程序。调试core文件是GDB的一个重要功能,c…

NewStar_Week3_Web

whossti SSTI也是CTF中一个经典的考点 这里我们就简单讲一下原理,深入探索得靠你们自己了 SSTI(Server-Side Template Injection,服务端模板注入)是一种严重的Web安全漏洞,它允许攻击者利用应用程序中的模板引擎执…

你真的知道你正在运行哪个 PostgreSQL吗?

本文整理自 IvorySQL 2025 生态大会暨 PostgreSQL 高峰论坛的演讲分享,演讲嘉宾:Alvaro Hernandez。个人简介:OnGres 创始人&CEO 20年以上Postgres用户及数据库管理员经验 主要从事研发工作,基于Postgr0 es创建…

2025年污水处理设备厂家权威推荐榜单:盐湖提锂技术/扩散渗析器/扩散渗析系统源头厂家精选

在环保政策持续收紧与绿色发展理念深入人心的背景下,工业及市政污水处理需求正经历从"达标排放"向"资源化利用"的深刻转变。本文将基于2025年行业技术标准与市场趋势,为您深入分析污水处理设备前…

docker容器oshi如何获取宿主机的运行状态信息?

If the app is running in Docker, will the result obtained by Oshi be information about the operating system or the Docker container oshi oshi.properties复制请注明出处,在世界中挣扎的灰太狼

Java 应用 DevOps 全流程(CICD)闭环 - docker-compose版

🧩 一、项目结构 一个典型的 Java + Docker Compose 项目可以这样组织: my-app/├── src/├── pom.xml├── Dockerfile├── docker-compose.yml└── Jenkinsfile🏗️ 二、1️⃣ 打包:Maven 构建 Sprin…

WebMvcConfigurationSupport vs WebMvcConfigurer 的本质区别

springboot项目中MVCconfiguration配置是继承WebMvcConfigurationSupport还是实现WebMvcConfigurer 呢?这两者有什么区别呢? WebMvcConfigurationSupportWebMvcConfigurationSupport 是 Spring MVC 的底层配置类,继…

成功拿到备案号 | 详述大模型备案

本文详解备案流程,旨在帮助企业和开发者顺利完成备案,确保企业成功拿到大模型备案号。 团队目前已经协助其他团队备案通过了多家大模型备案。 一、政策要求做大模型备案 大模型备案是中国国家互联网信息办公室为加强…

MATLAB与ModBus RTU设备进行串行通信

使用MATLAB与ModBus RTU设备进行串行通信的代码及说明,分为高级封装方法(推荐)和底层手动实现两种方案:一、高级封装方法(推荐,需Instrument Control Toolbox) 使用MATLAB内置的modbus对象简化通信流程,自动处…

2025年艾草贴厂家权威推荐榜单:老北京足贴/蒸汽眼罩/泡澡液源头生产厂家精选

艾草贴作为大健康领域的热门产品,凭借其简便的使用方法、温和的作用机理和明确的体验效果,在眼部护理、肩颈放松、足部保健等日常健康护理场景中发挥着重要作用。本文将基于个人护理用品行业标准与发展趋势,为您深入…

封装新纪元

在电子设计领域,IC 封装不仅是保护芯片的重要技术,更是推动微型化、性能提升与系统可靠的关键支撑。本文带你走进封装世界,从传统到未来趋势,感受封装技术如何推动电子不断进化。 1、封装类型一览与演进趋势 DIP(…

高精度板子

从网上当的 const int maxn = 50000; struct bign{ int d[maxn], len; void clean() { while(len > 1 && !d[len-1]) len--; } bign() { memset(d, 0, sizeof(d)); len = 1; } bign(int num)…

成都恒利泰宽带锥形电感,一颗顶三颗

成都恒利泰宽带锥形电感,一颗顶三颗2015年,成都诞生了一家专注于射频无源器件的公司——成都恒利泰科技有限公司,在研发、制造和销售上提供 20多条产品线包括:LTCC/LC滤波器、功分器、巴伦变压器、耦合器、射频转接…

微算法科技(NASDAQ MLGO)采用动态层次管理和位置聚类技术,修改pBFT算法以提高私有区块链网络运行效率

在数字化转型加速的背景下,私有区块链网络面临着效率与扩展性的双重挑战。传统实用拜占庭容错算法(pBFT)在节点规模扩大时,通信复杂度呈指数级增长,导致共识时延增加和资源消耗加剧。与此同时,静态网络架构无法动…