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