扣了钱,对方没到账?

发布 · 视频 1:15 · 约 2 分钟读完 · #后端#数据库#事务

章节

  1. 0:00扣了没到
  2. 0:07拆成两步
  3. 0:21同一个包裹
  4. 0:33封箱
  5. 0:43倒着撤回
  6. 0:54不能拆一半
  7. 1:05回顾

快捷键:K/空格 播放暂停 · J/L 上/下一章 · ↑/↓ 切换章节

扣了钱,对方没到账?

1. 扣了没到

你给朋友转 100 块,你这边扣了,他那边却没收到。这是事务要解决的经典问题,PostgreSQL 官方教程用的也是转账 100 的例子。1

2. 拆成两步

一次转账至少包含两次更新:给 A 扣钱,给 B 加钱。如果中途出了故障,只完成了第一步,就会出现「扣了没到」。12

3. 事务:同一个包裹

事务把多个步骤打包成一个「要么全做、要么全不做」的整体。13 MySQL 默认开着自动提交(autocommit),每条语句会自己成为一个事务。要把扣钱和加钱绑在一起,得用 START TRANSACTION(或 BEGIN)开头。45

SQL
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE name = 'A';
UPDATE accounts SET balance = balance + 100 WHERE name = 'B';
COMMIT;

4. 提交:封箱

COMMIT 让本次事务的修改永久生效,并且让其他会话看得到。45

5. 回滚:倒着撤回

ROLLBACK 取消本次事务里的全部修改。4 数据库其实已经改过数据了:InnoDB 改数据时会把旧值记进 undo 日志,回滚就是按这些记录把每一步倒着撤回。63 注意:自动提交模式下,单条语句已经提交,不能再用 ROLLBACK 撤销。4

6. 原子性:不能拆一半

事务要么全部完成,要么完全没发生,不存在只做一半的事务,这叫原子性。31

延伸:ACID 的另外三个字母

  • 一致性(C):MySQL 词汇表的说法是,数据始终处于一致状态,查询看到的要么全是旧值、要么全是新值,不会新旧混在一起。3 另一种常见讲法是事务结束时数据要满足所有规则,比如不能只给一个账户入账。27 不同资料对 C 的解释角度不一样。
  • 隔离性(I):进行中的事务彼此隔离,能看到别人多少改动由隔离级别决定;读已提交及以上看不到对方没提交的数据(读未提交可以,这就是下一期讲的脏读)。3 SQL 标准定义了 4 个隔离级别,InnoDB 默认可重复读8,PostgreSQL 默认读已提交。9
  • 持久性(D):提交成功后,改动不会因为断电或崩溃丢失。3 这一点和配置、硬件都有关,在默认的安全配置下才成立。10

延伸:崩溃了怎么办

数据库重启时,会先用 redo 日志把崩溃前记下的修改重做一遍(其中可能有没提交的),再用 undo 回滚崩溃时还没提交的事务。1112

Footnotes

  1. PostgreSQL 18 文档 3.4 Transactions https://www.postgresql.org/docs/current/tutorial-transactions.html ↩ ↩2 ↩3 ↩4

  2. Oracle AI Database 26 Concepts, Transactions(2026-04-30)https://docs.oracle.com/en/database/oracle/oracle-database/26/cncpt/transactions.html ↩ ↩2

  3. MySQL 8.4 手册 Glossary(2026-10-01 生成)https://dev.mysql.com/doc/refman/8.4/en/glossary.html ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  4. MySQL 8.4 手册 15.3.1 START TRANSACTION, COMMIT, and ROLLBACK(2026-10-01 生成)https://dev.mysql.com/doc/refman/8.4/en/commit.html ↩ ↩2 ↩3 ↩4

  5. MySQL 8.4 手册 17.7.2.2 autocommit, Commit, and Rollback(2026-10-01 生成)https://dev.mysql.com/doc/refman/8.4/en/innodb-autocommit-commit-rollback.html ↩ ↩2

  6. MySQL 8.4 手册 17.6.6 Undo Logs(2026-10-01 生成)https://dev.mysql.com/doc/refman/8.4/en/innodb-undo-logs.html ↩

  7. Microsoft Learn, Transaction Locking and Row Versioning Guide(2026-09-22)https://learn.microsoft.com/en-us/sql/relational-databases/sql-server-transaction-locking-and-row-versioning-guide?view=sql-server-ver17 ↩

  8. MySQL 8.4 手册 17.7.2.1 Transaction Isolation Levels(2026-10-01 生成)https://dev.mysql.com/doc/refman/8.4/en/innodb-transaction-isolation-levels.html ↩

  9. PostgreSQL 18 文档 13.2 Transaction Isolation https://www.postgresql.org/docs/current/transaction-iso.html ↩

  10. MySQL 8.4 手册 17.2 InnoDB and the ACID Model(2026-10-01 生成)https://dev.mysql.com/doc/refman/8.4/en/mysql-acid.html ↩

  11. MySQL 8.4 手册 17.6.5 Redo Log(2026-10-01 生成)https://dev.mysql.com/doc/refman/8.4/en/innodb-redo-log.html ↩

  12. MySQL 8.4 手册 17.18.2 InnoDB Recovery(2026-10-01 生成)https://dev.mysql.com/doc/refman/8.4/en/innodb-recovery.html ↩

幕后

这部片子完全由代码生成。