课程 › 第 9 章 › 实验一
第 9 章 · 实验一 · 在第一节之后

事务的提交与回滚

在一个窗口中练习事务:先看自动提交模式,再用 START TRANSACTION、ROLLBACK、COMMIT 控制事务,最后执行一次完整的转账事务。

环 境

MySQL 8.0 和 MySQL Workbench,机房电脑已装好。所有语句在 Workbench 的 SQL 编辑区中执行。

执 行

Ctrl+Enter 执行光标所在的一句,Ctrl+Shift+Enter 执行全部。Mac 上把 Ctrl 换成 ⌘。

注 意

输入法切到英文。表名、字段名不加引号,字符串值才用单引号。

本次实验的顺序 后一个实验用到前一个的结果

  1. 实验 1-1自动提交模式
  2. 实验 1-2回滚事务
  3. 实验 1-3提交事务
  4. 实验 1-4转账事务
  5. 实验 1-5连接断开时的事务
第一步

数据准备(必做)

新建银行账户库 bankaccount 和账户表 account,装入三个账户:account1 500 元,account2 900 元,account3 900 元。三次实验共用这份脚本,每次实验前执行一次,数据回到初始状态。

整段复制,全部执行下载 .sql
-- 第 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;
1-1

自动提交模式

讲义 · 事务的概念
目的
查看自动提交模式,验证自动提交时每一条语句执行后就不能回滚。
前提
已执行数据准备,当前库是 bankaccount。
  1. 查看自动提交是否打开
  2. 把 account3 的余额减少 50,再执行 ROLLBACK,查看余额
  3. 把 account3 的余额加回 50

参考答案

可以直接复制到 Workbench 执行
SELECT @@autocommit;
UPDATE account SET R = R - 50
WHERE id = 'account3';
-- 自动提交模式下,上一句已经提交,这句回滚不起作用
ROLLBACK;
SELECT * FROM account;
-- 恢复原来的余额
UPDATE account SET R = R + 50
WHERE id = 'account3';

语句解释

@@autocommit1 表示自动提交打开,这是 MySQL 的默认设置
自动提交每一条语句单独作为一个事务,执行成功就立即提交
ROLLBACK没有开始事务时,ROLLBACK 没有可以撤销的操作
执行后看:@@autocommit 为 1。ROLLBACK 之后 account3 仍是 850,说明 UPDATE 已经提交。最后一句把它恢复为 900。
1-2

回滚事务

讲义 · 事务的概念
目的
用 START TRANSACTION 开始事务,用 ROLLBACK 撤销事务中的修改。
前提
已完成实验 1-1。
  1. 开始一个事务,把 account1 的余额减少 100,查看余额
  2. 回滚事务,再查看余额

参考答案

可以直接复制到 Workbench 执行
START TRANSACTION;
UPDATE account SET R = R - 100
WHERE id = 'account1';
SELECT * FROM account;
-- 撤销这个事务中的全部修改
ROLLBACK;
SELECT * FROM account;

语句解释

START TRANSACTION开始一个事务,之后的修改要等 COMMIT 才提交
ROLLBACK撤销事务中所做的全部修改,并结束事务
执行后看:事务中查到 account1 是 400。回滚后又回到 500。
1-3

提交事务

讲义 · 事务的概念讲义 · ACID
目的
用 COMMIT 提交事务,验证提交以后不能再回滚。
前提
已完成实验 1-2。
  1. 开始一个事务,给 account3 的余额增加 100,提交事务
  2. 执行 ROLLBACK,再查看余额

参考答案

可以直接复制到 Workbench 执行
START TRANSACTION;
UPDATE account SET R = R + 100
WHERE id = 'account3';
COMMIT;
-- 事务已经提交,这句回滚不起作用
ROLLBACK;
SELECT * FROM account;

语句解释

COMMIT提交事务,事务中的修改永久保存,事务结束
提交后的 ROLLBACK已经没有未提交的事务,不能撤销
执行后看:account3 变为 1000,ROLLBACK 没有把它改回去。
1-4

转账事务

讲义 · 转账事务讲义 · ACID
目的
按课件的转账事务,把 account1 的 100 元转给 account2,验证转账前后两个账户的总额不变。
前提
已完成实验 1-3。
  1. 查询 account1 和 account2 的总额
  2. 在一个事务中完成转账:account1 减少 100,account2 增加 100,同时更新两个账户的操作时间
  3. 提交后再查询两个账户的总额

参考答案

可以直接复制到 Workbench 执行
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,这就是一致性
执行后看:转账后 account1 是 400,account2 是 1000,两个账户的 datetime 变为当前时间。两次求和都是 1400。
1-5

连接断开时的事务

讲义 · ACID
目的
事务没有提交时断开连接,验证事务中的修改会被撤销。
前提
已完成实验 1-4。

执行完第一段后,关掉这个连接标签页,再从 Workbench 首页重新打开连接,执行第二段。

  1. 开始一个事务,把 account1 的余额减少 100,查看余额,不提交
  2. 关掉连接后重新连接,查看 account1 的余额

参考答案

第一段:开始事务,不提交
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 自动回滚这个连接中未提交的事务
原子性事务中的操作要么全部完成,要么全部不做,做了一半的会被撤销
执行后看:第一段查到 account1 是 300。重新连接后查到的是 400,减少的 100 元被撤销了。
保山学院·人工智能教研室·曹鼎鼎