【数据库基础】转账100块怎么丢了?通俗讲解数据库事务ACID特性

简介: 本文深入浅出地讲解数据库事务的ACID四大特性。以转账场景为例,介绍事务“要么全成功,要么全失败”的核心思想。详解原子性(Undo Log回滚)、一致性(数据守恒)、隔离性(并发控制)与持久性(Redo Log保障),助你理解数据库可靠性的基石。

前言

在上一篇关于 InnoDB 的文章中,我们提到 InnoDB 相比 MyISAM 最大的优势之一就是支持事务(Transaction)

初学者往往觉得“事务”这个词很高大上,但其实它解决的问题非常接地气。

试想一个场景:A 向 B 转账 100 元。 在数据库层面,这其实是两步操作:

  1. A 的账户余额减去 100 元。
  2. B 的账户余额加上 100 元。

如果在第1步执行完后,服务器突然断电了,或者程序报错了,第2步没执行。结果就是:A 的钱少了,B 的钱也没收到,这就出大事了。

为了解决这个问题,数据库引入了事务的概念。简单来说,事务就是**“一组操作,要么全部成功,要么全部失败,决不允许只做一半”**。

为了衡量一个数据库是否支持事务,计算机科学家提出了著名的 ACID 四大特性。

1. Atomicity(原子性)—— 同生共死

  • 定义: 事务包含的所有操作,要么全部执行成功,要么全部失败回滚(Rollback)。
  • 通俗解释: 就像原子是不可分割的一样,事务里的操作也是一个整体。
  • 案例: 转账过程中,A 扣款成功,但在 B 加钱之前系统崩了。数据库会监测到这个事务没有完成,于是自动把 A 扣掉的钱退回去(回滚),就像这件事从来没发生过一样。
  • 底层原理:Undo Log(回滚日志)实现。每做一步操作,数据库都记了个小本本,一旦失败,就反向操作把数据改回去。

代码示例(Spring):

Java

@Transactional // 开启事务
public void transfer(int fromId, int toId, double amount) {
    // 1. A 扣款
    userDao.decrementBalance(fromId, amount);
    
    // 模拟一个异常(比如除以0,或者断电)
    int i = 1 / 0; 
    
    // 2. B 加钱(由于上面报错,这行代码不会执行,且第1步会自动回滚)
    userDao.incrementBalance(toId, amount);
}

2. Consistency(一致性)—— 守规矩

  • 定义: 事务执行前后,数据库的完整性约束没有被破坏。
  • 通俗解释: 能量守恒定律。
  • 案例:
  • A 有 500 元,B 有 0 元。
  • 无论怎么转账,只要钱没转出银行系统,A 和 B 的余额总和永远应该是 500 元。
  • 如果转账完,A 剩 400,B 变成了 200,总和变 600 了,那就是破坏了一致性。
  • 另外,如果数据库规定余额不能为负数,那么 A 余额只有 100 却要转 200,事务必须失败,这也是一致性。

3. Isolation(隔离性)—— 各玩各的

  • 定义: 多个事务并发执行时,不应互相干扰。
  • 通俗解释: 你在ATM机上查余额,你老婆正好在用支付宝刷你的卡消费。这两个操作同时进行,应该互相隔离,不能让你看到的数据乱套。
  • 并发带来的问题:
  • 脏读: 你读到了别人还没提交的数据(万一他回滚了,你读的就是假数据)。
  • 不可重复读: 一个事务内两次读到的数据不一样。
  • 幻读: 一个事务内读到的行数不一样。
  • 解决办法: 数据库提供了 4 种隔离级别(Read Uncommitted, Read Committed, Repeatable Read, Serializable)来平衡性能与隔离性。MySQL InnoDB 默认使用的是 Repeatable Read(可重复读)

4. Durability(持久性)—— 落袋为安

  • 定义: 事务一旦提交(Commit),它对数据的修改就是永久的。
  • 通俗解释: 只要你看到了“交易成功”四个字,哪怕下一秒机房爆炸、服务器被雷劈了,你的钱也确确实实转过去了,数据绝不会丢失。
  • 底层原理:Redo Log(重做日志)实现。上一篇文章提到过,数据修改会先写日志。只要日志在磁盘上,重启后数据库就能根据日志重新构建数据。

总结

面试时如果你能用这个逻辑讲出来,稳过:

  • 原子性 (A):要么全做,要么全不做(靠 Undo Log)。
  • 持久性 (D):由于断电等原因,已提交的数据不能丢(靠 Redo Log)。
  • 隔离性 (I):并发事务之间互不干扰(靠 锁 和 MVCC)。
  • 一致性 (C):这是最终目的。原子性、隔离性、持久性都是为了保证数据的一致性。
相关文章
|
9月前
|
SQL 监控 druid
【性能优化】拒绝性能瓶颈!数据库连接池配置详解与调优实战
本文深入讲解数据库连接池核心原理与调优技巧,涵盖HikariCP和Druid配置要点,解析四大关键参数、黄金连接数公式及Druid监控功能,助你科学设置连接池,避免性能瓶颈。
|
9月前
|
消息中间件 缓存 NoSQL
【Redis进阶】不止是缓存!Redis的5种核心数据结构与实战场景全解析
本文深入浅出地解析了Redis五大核心数据结构:String、Hash、List、Set和ZSet,结合图解与实战场景,涵盖缓存、计数器、分布式锁、购物车、消息队列、排行榜等典型应用,助你摆脱“只会SET/GET”的困境,真正发挥Redis的高性能潜力。
|
6月前
|
人工智能 弹性计算 安全
阿里云最新云产品组合购活动参考:云服务器ECS、域名、建站、AI等相关产品组合套餐
阿里云组合GO活动提供精选云产品组合,覆盖90%以上上云场景,组合购买享超值折扣。活动包括AI模型服务与推理,助力AI应用快速创新;15元AI建站套餐,含云资源和.CN域名;热卖场景组合购,助力开发者高效上云;还有轻松部署服务,快速搭建自有网站。同时,提供全方位安全防护,保障业务稳定运行,以及精准数据分析与高效迁移服务,打造无忧开发体验。阿里云为开发者及企业提供高效、安全、经济的上云解决方案。
590 4
|
11月前
|
设计模式 网络协议 数据可视化
Java 设计模式之状态模式:让对象的行为随状态优雅变化
状态模式通过封装对象的状态,使行为随状态变化而改变。以订单为例,将待支付、已支付等状态独立成类,消除冗长条件判断,提升代码可维护性与扩展性,适用于状态多、转换复杂的场景。
1136 157
|
6月前
|
消息中间件 存储 缓存
如何优化代码以提高淘宝商品详情API的调用效率?
优化淘宝商品详情 API(如taobao.item_get)的调用效率,核心是“减少无效请求、提升单次请求价值、降低调用耗时”,从「请求策略、代码层优化、架构设计、数据复用」四个维度落地,以下是可直接嵌入代码的实操方案,兼顾效率与平台规则:
|
9月前
|
关系型数据库 MySQL Nacos
CAP原理
本节介绍分布式事务中的CAP原理,即一致性(C)、可用性(A)、分区容忍性(P)三者不可兼得。分布式系统必须满足P,因此需在C与A之间权衡,选择CP或AP方案。内容结合金融、库存、订票等实际场景,解析Zookeeper、Redis、Nacos等技术的选型应用,指导如何根据业务需求合理选择分布式事务控制策略。
CAP原理
|
9月前
|
消息中间件 关系型数据库 MySQL
MySQL 微服务架构实践:从单库到多库的分布式适配
本文详解MySQL在微服务架构下的适配实践,涵盖服务拆分原则、数据同步方案与分布式事务解决方案。通过电商案例,解析如何实现数据隔离、最终一致性及高并发场景下的事务管理,助力开发者应对分布式数据挑战。
|
9月前
|
SQL 存储 关系型数据库
数据库的行级锁与表锁
表锁无死锁,但并发低,读写互斥;行锁基于索引,支持高并发,但可能死锁。若SQL未走索引,行锁失效转为表锁。行锁适用于避免不可重复读,事务中增删改自动加排他锁,且不可锁定同一索引。
|
9月前
|
SQL Dubbo Java
线程池:常见故障
本文从故障与技术双重视角,总结线程池类问题的常见成因与规避方案。重点分析数据库慢查询、连接池配置不当、自定义线程池使用误区等典型故障,结合真实案例,提炼出fast-fail、超时控制、资源隔离、流控背压等核心防护策略,助力开发者提升系统稳定性。
|
机器学习/深度学习 传感器 算法
【雷达信号分析】基于单载频矩形脉冲信号时频分析附Matlab代码
【雷达信号分析】基于单载频矩形脉冲信号时频分析附Matlab代码
698 0