在一个窗口中练习事务:先看自动提交模式,再用 START TRANSACTION、ROLLBACK、COMMIT 控制事务,最后执行一次完整的转账事务。
MySQL 8.0 和 MySQL Workbench,机房电脑已装好。所有语句在 Workbench 的 SQL 编辑区中执行。
Ctrl+Enter 执行光标所在的一句,Ctrl+Shift+Enter 执行全部。Mac 上把 Ctrl 换成 ⌘。
输入法切到英文。表名、字段名不加引号,字符串值才用单引号。
新建银行账户库 bankaccount 和账户表 account,装入三个账户:account1 500 元,account2 900 元,account3 900 元。三次实验共用这份脚本,每次实验前执行一次,数据回到初始状态。
-- 第 9 章实验数据:银行账户库 bankaccount 和账户表 account -- 三次实验共用。整段执行一次即可,想从头再做时重新执行。 CREATE DATABASE IF NOT EXISTS bankaccount DEFAULT CHARACTER SET utf8mb4; USE bankaccount; DROP TABLE IF EXISTS account; -- id 账户号,R 余额,datetime 最近一次操作的时间 CREATE TABLE account ( id VARCHAR(20) NOT NULL, R DECIMAL(10,2) NOT NULL, datetime DATETIME, PRIMARY KEY (id) ); INSERT INTO account VALUES ('account1', 500.00, '2026-09-01 09:00:00'), ('account2', 900.00, '2026-09-01 09:00:00'), ('account3', 900.00, '2026-09-01 09:00:00'); SELECT * FROM account;
SELECT @@autocommit; UPDATE account SET R = R - 50 WHERE id = 'account3'; -- 自动提交模式下,上一句已经提交,这句回滚不起作用 ROLLBACK; SELECT * FROM account; -- 恢复原来的余额 UPDATE account SET R = R + 50 WHERE id = 'account3';
| @@autocommit | 1 表示自动提交打开,这是 MySQL 的默认设置 |
| 自动提交 | 每一条语句单独作为一个事务,执行成功就立即提交 |
| ROLLBACK | 没有开始事务时,ROLLBACK 没有可以撤销的操作 |
START TRANSACTION; UPDATE account SET R = R - 100 WHERE id = 'account1'; SELECT * FROM account; -- 撤销这个事务中的全部修改 ROLLBACK; SELECT * FROM account;
| START TRANSACTION | 开始一个事务,之后的修改要等 COMMIT 才提交 |
| ROLLBACK | 撤销事务中所做的全部修改,并结束事务 |
START TRANSACTION; UPDATE account SET R = R + 100 WHERE id = 'account3'; COMMIT; -- 事务已经提交,这句回滚不起作用 ROLLBACK; SELECT * FROM account;
| COMMIT | 提交事务,事务中的修改永久保存,事务结束 |
| 提交后的 ROLLBACK | 已经没有未提交的事务,不能撤销 |
SELECT SUM(R) FROM account WHERE id IN ('account1', 'account2'); START TRANSACTION; SELECT R FROM account WHERE id = 'account1'; UPDATE account SET R = R - 100 WHERE id = 'account1'; UPDATE account SET datetime = NOW() WHERE id = 'account1'; SELECT R FROM account WHERE id = 'account2'; UPDATE account SET R = R + 100 WHERE id = 'account2'; UPDATE account SET datetime = NOW() WHERE id = 'account2'; COMMIT; SELECT * FROM account; SELECT SUM(R) FROM account WHERE id IN ('account1', 'account2');
| UPDATE … R = R - 100 WHERE id = 'account1' | 从 account1 转出 100 元 |
| datetime = NOW() | NOW() 返回当前的日期和时间,记下这次操作的时间 |
| START TRANSACTION … COMMIT | 六个操作放在一个事务中,要么全部完成,要么全部不做 |
| SUM(R) | 转账前后两个账户的总额都是 1400,这就是一致性 |
执行完第一段后,关掉这个连接标签页,再从 Workbench 首页重新打开连接,执行第二段。
START TRANSACTION; UPDATE account SET R = R - 100 WHERE id = 'account1'; SELECT * FROM account WHERE id = 'account1';
USE bankaccount; SELECT * FROM account WHERE id = 'account1';
| 不写 COMMIT | 事务一直没有提交 |
| 关掉连接 | 连接断开时,MySQL 自动回滚这个连接中未提交的事务 |
| 原子性 | 事务中的操作要么全部完成,要么全部不做,做了一半的会被撤销 |