事务操作

最近更新时间:2026-02-05 11:01:13

我的收藏

开启事务

在 TDSQL Boundless 中,用户可以通过以下三种方式开启一个事务:
1. 使用 BEGIN 语句
BEGIN;
2. 使用 START TRANSACTION 语句
START TRANSACTION;
3. 关闭自动提交模式
SET autocommit=0;
注意:
使用 SET autocommit=0 后,所有后续 SQL 语句都将在一个事务中执行,直到显式执行 COMMITROLLBACK
在用户执行开启事务语句后,数据库不会立刻为事务分配快照。快照是在用户执行第一条读写 SQL 时分配给事务的。

执行事务中的 SQL 操作

开启事务后,可以执行各种 SQL 语句,这些操作将暂时保存在事务上下文中,无法被其它事务感知,直到提交或回滚。
START TRANSACTION;

-- 更新用户表
UPDATE users SET balance = balance - 100 WHERE user_id = 1;

-- 插入订单记录
INSERT INTO orders (user_id, amount, order_date)
VALUES (1, 100, NOW());

提交事务

当所有操作都成功执行后,可以使用 COMMIT 语句提交事务:
COMMIT;
提交后,事务中的所有操作将永久保存到数据库中。

回滚事务

如果在事务执行过程中遇到错误或需要取消操作,可以使用 ROLLBACK 语句回滚事务:
ROLLBACK;
回滚后,事务中的所有操作将被撤销,数据库恢复到事务开始前的状态。

SAVEPOINT 操作

SAVEPOINT 是数据库事务管理中的一项重要功能,允许在事务执行过程中创建标记点,以便在需要时可以回滚到特定标记点,而不必回滚整个事务。

创建保存点

SAVEPOINT savepoint_name;

回滚到保存点

ROLLBACK TO SAVEPOINT savepoint_name;

释放保存点

RELEASE SAVEPOINT savepoint_name;

示例

本节将基于一个银行账户转账的场景,详细演示事务的各项操作。
1. 创建示例表并初始化数据。
-- 创建测试表
CREATE TABLE bank_account (
account_id VARCHAR(20) PRIMARY KEY,
account_name VARCHAR(50),
balance DECIMAL(15, 2)
);

-- 插入初始数据
INSERT INTO bank_account VALUES
('1001', '张三', 5000.00),
('1002', '李四', 3000.00);
2. 事务操作演示。
-- 1. 开始一个事务
START TRANSACTION;

-- 查看初始余额
SELECT * FROM bank_account WHERE account_id IN ('1001', '1002');
+------------+--------------+---------+
| account_id | account_name | balance |
+------------+--------------+---------+
| 1001 | 张三 | 5000.00 |
| 1002 | 李四 | 3000.00 |
+------------+--------------+---------+
2 rows in set (0.00 sec)

-- 2. 创建第一个保存点(在扣款前)
SAVEPOINT before_debit;

-- 3. 从张三账户扣款1000元
UPDATE bank_account SET balance = balance - 1000 WHERE account_id = '1001';

-- 4. 创建第二个保存点(扣款后,存款前)
SAVEPOINT after_debit;

-- 5. 向李四账户存款1000元
UPDATE bank_account SET balance = balance + 1000 WHERE account_id = '1002';

-- 检查当前事务内的账户余额
SELECT * FROM bank_account WHERE account_id IN ('1001', '1002');
+------------+--------------+---------+
| account_id | account_name | balance |
+------------+--------------+---------+
| 1001 | 张三 | 4000.00 |
| 1002 | 李四 | 4000.00 |
+------------+--------------+---------+
2 rows in set (0.00 sec)

-- 假设此时发现李四账户状态异常,需要回滚到存款操作之前
-- 6. 回滚到第二个保存点(这将撤销存款操作,但保留扣款操作)
ROLLBACK TO SAVEPOINT after_debit;

-- 检查回滚后的余额(李四账户金额未变)
SELECT * FROM bank_account WHERE account_id IN ('1001', '1002');
+------------+--------------+---------+
| account_id | account_name | balance |
+------------+--------------+---------+
| 1001 | 张三 | 4000.00 |
| 1002 | 李四 | 3000.00 |
+------------+--------------+---------+
2 rows in set (0.00 sec)

-- 7. 由于业务规则要求转账必须完整,我们决定回滚整个事务
ROLLBACK; -- 回滚到事务开始状态,所有操作撤销

-- 最终确认数据是否恢复原状
SELECT * FROM bank_account WHERE account_id IN ('1001', '1002');
+------------+--------------+---------+
| account_id | account_name | balance |
+------------+--------------+---------+
| 1001 | 张三 | 5000.00 |
| 1002 | 李四 | 3000.00 |
+------------+--------------+---------+
2 rows in set (0.00 sec)

-- 8. 重新开始事务并进行完整转账
START TRANSACTION;

UPDATE bank_account SET balance = balance - 1000 WHERE account_id = '1001';
UPDATE bank_account SET balance = balance + 1000 WHERE account_id = '1002';

-- 9. 确认无误后提交事务,使更改永久生效
COMMIT;

-- 最终确认数据修改是否生效
SELECT * FROM bank_account WHERE account_id IN ('1001', '1002');
+------------+--------------+---------+
| account_id | account_name | balance |
+------------+--------------+---------+
| 1001 | 张三 | 4000.00 |
| 1002 | 李四 | 4000.00 |
+------------+--------------+---------+
2 rows in set (0.00 sec)