扣了钱,对方没到账?
1. 扣了没到
你给朋友转 100 块,你这边扣了,他那边却没收到。这是事务要解决的经典问题,PostgreSQL 官方教程用的也是转账 100 的例子。1
2. 拆成两步
一次转账至少包含两次更新:给 A 扣钱,给 B 加钱。如果中途出了故障,只完成了第一步,就会出现「扣了没到」。12
3. 事务:同一个包裹
事务把多个步骤打包成一个「要么全做、要么全不做」的整体。13
MySQL 默认开着自动提交(autocommit),每条语句会自己成为一个事务。要把扣钱和加钱绑在一起,得用 START TRANSACTION(或 BEGIN)开头。45
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
-
PostgreSQL 18 文档 3.4 Transactions https://www.postgresql.org/docs/current/tutorial-transactions.html ↩ ↩2 ↩3 ↩4
-
Oracle AI Database 26 Concepts, Transactions(2026-04-30)https://docs.oracle.com/en/database/oracle/oracle-database/26/cncpt/transactions.html ↩ ↩2
-
MySQL 8.4 手册 Glossary(2026-10-01 生成)https://dev.mysql.com/doc/refman/8.4/en/glossary.html ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
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
-
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
-
MySQL 8.4 手册 17.6.6 Undo Logs(2026-10-01 生成)https://dev.mysql.com/doc/refman/8.4/en/innodb-undo-logs.html ↩
-
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 ↩
-
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 ↩
-
PostgreSQL 18 文档 13.2 Transaction Isolation https://www.postgresql.org/docs/current/transaction-iso.html ↩
-
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 ↩
-
MySQL 8.4 手册 17.6.5 Redo Log(2026-10-01 生成)https://dev.mysql.com/doc/refman/8.4/en/innodb-redo-log.html ↩
-
MySQL 8.4 手册 17.18.2 InnoDB Recovery(2026-10-01 生成)https://dev.mysql.com/doc/refman/8.4/en/innodb-recovery.html ↩
幕后
这部片子完全由代码生成。
系列 · 数据库第 2/6 期