一、开启事务
1. 使用 BEGIN 语句
BEGIN;
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)