记一次模拟断电,事务回滚。

本文探讨了在代码中断点后程序中断导致事务不回滚的问题,分析了事务不会回滚的常见原因,包括调用自身类方法和使用非InnoDB数据库。并通过模拟断电测试,验证事务的正常回滚机制。

在代码中部下断点后中断程序,事务是不会回滚的,这样会污染数据。暂时不理解事务不会回滚的原因。

模拟断电应该用线程休眠,然后直接中断程序,这样可以看到事务确实有正常回滚。

 

 

不会回滚的原因一般基本就是

1.调用了自身类方法这样是不会回滚的。这个很容易知道,毕竟AOP。

2.数据库不是inndb。

### 事务提交后能否回滚?—— 深入解析 **直接回答:一旦事务被正式提交(COMMIT),就绝对不能再回滚了!** 让我通过代码和原理来详细解释: #### 1. 提交即不可逆的验证实验 ```sql -- 创建测试表 DROP TABLE IF EXISTS test_rollback; CREATE TABLE test_rollback ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50), value INT DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB; INSERT INTO test_rollback (name, value) VALUES ('初始录', 100); -- 查看初始状态 SELECT 'before_transaction' as stage, * FROM test_rollback; ``` ##### 场景A:未提交时可以回滚 ✅ ```sql START TRANSACTION; UPDATE test_rollback SET value = 200 WHERE name = '初始录'; INSERT INTO test_rollback (name, value) VALUES ('新录', 50); -- 此时可以查看变化(仅本会话可见) SELECT 'after_update_before_commit' as stage, * FROM test_rollback; -- 执行回滚 - 成功恢复原状! ROLLBACK; -- 验证:回到最初状态 SELECT 'after_rollback' as stage, * FROM test_rollback; -- 只有最初的那条录,value还是100 ``` ##### 场景B:已提交后无法回滚 ❌ ```sql START TRANSACTION; UPDATE test_rollback SET value = 300 WHERE name = '初始录'; INSERT INTO test_rollback (name, value) VALUES ('提交的录', 80); -- 关键步骤:提交事务! COMMIT; -- 尝试回滚 - 这里会出错或无效! -- ROLLBACK; -- 即使执行也不会有任何效果 -- 查询结果:修改永久生效! SELECT 'after_commit' as stage, * FROM test_rollback; -- 显示两条录,value为300和80,永远改变了! ``` #### 2. 为什么提交后不能回滚? ```sql -- 原理:InnoDB的事务日志机制 -- 当执行 COMMIT 时会发生什么? -- 1. REDO LOG 写入磁盘 -- 2. 数据页标为已修改 -- 3. 释放行锁 -- 4. 事务状态变为"已提交" -- 验证REDO日志的影响 SHOW ENGINE INNODB STATUS\G -- 查看 "LOG" 部分,会显示: -- Log sequence number: ... (持续增长) ``` #### 3. 提交后的"补救"方案 虽然不能直接回滚,但可以通过其他方式修复: ##### 方案1:反向操作(推荐) ```sql -- 如果错误地执行了: START TRANSACTION; UPDATE test_rollback SET value = 999 WHERE name = '初始录'; COMMIT; -- 补救方法:执行相反的更新 START TRANSACTION; UPDATE test_rollback SET value = 300 WHERE name = '初始录'; -- 恢复正确值 INSERT INTO operation_log VALUES ( NULL, 'manual_correction', '修正错误的更新操作', NOW() ); COMMIT; ``` ##### 方案2:使用binlog进行时间点恢复 ```bash # MySQL必须开启binlog # my.cnf配置: # log-bin=mysql-bin # binlog-format=ROW # 查看binlog内容 mysqlbinlog --start-datetime="2025-12-14 07:00:00" \ --stop-datetime="2025-12-14 07:10:00" \ mysql-bin.000001 > recovery.sql # 编辑recovery.sql,删除错误的COMMIT之后的操作 # 然后重新导入 mysql -u root -p mydb < recovery.sql ``` ##### 方案3:基于备份的恢复 ```sql -- 定期备份策略 mysqldump -u root -p --single-transaction mydb > backup_$(date +%Y%m%d).sql -- 如果发生重大错误,从备份恢复 mysql -u root -p mydb < backup_20251213.sql ``` #### 4. 防御性编程:提交前的确认机制 ```sql DELIMITER // CREATE PROCEDURE safe_update_with_confirmation( IN target_name VARCHAR(50), IN new_value INT ) BEGIN DECLARE current_value INT; DECLARE confirm_input VARCHAR(10); -- 开始事务 START TRANSACTION; -- 查询当前值 SELECT value INTO current_value FROM test_rollback WHERE name = target_name FOR UPDATE; SELECT CONCAT('即将修改: ', target_name) as info; SELECT CONCAT('原值: ', current_value) as info; SELECT CONCAT('新值: ', new_value) as info; -- 实际应用中这里应该返回给前端让用户确认 -- 模拟用户输入确认 SET confirm_input = 'yes'; -- 应该来自用户输入 IF confirm_input != 'yes' THEN ROLLBACK; SELECT '操作已取消' as result; ELSE UPDATE test_rollback SET value = new_value WHERE name = target_name; COMMIT; SELECT '更新成功' as result; END IF; END// DELIMITER ; -- 使用示例 CALL safe_update_with_confirmation('初始录', 500); ``` #### 5. 生产环境的最佳实践 ```sql -- 1. 设置长事务监控 SET SESSION innodb_lock_wait_timeout = 30; SET SESSION wait_timeout = 28800; -- 2. 提交前二次确认 SET SQL_SAFE_UPDATES = 1; -- 防止无WHERE条件的UPDATE -- 3. 使用保存点进行细粒度控制 START TRANSACTION; SAVEPOINT sp1; UPDATE test_rollback SET value = 1000 WHERE name = '初始录'; SAVEPOINT sp2; INSERT INTO test_rollback VALUES (NULL, '临时录', 999, NULL); -- 如果只想回滚到sp2 -- ROLLBACK TO sp2; -- 可以撤销INSERT,保留UPDATE -- 但一旦COMMIT,所有SAVEPOINT都失效! COMMIT; ``` #### 6. 重要警告:不要依赖自动回滚 ```sql -- 错误观念: -- "反正可以回滚,先试试看" -- 真实情况: START TRANSACTION; UPDATE huge_table SET status = 'processed' WHERE create_date < '2024-01-01'; -- 处理百万行数据... COMMIT; -- 提交后发现错了! -- 结果:无法挽回,只能手动修复或从备份恢复 ``` ### 核心结论: 1. **COMMIT = 不归路** - 一旦提交,修改永久生效 - REDO LOG确保即使断电也能恢复 2. **预防胜于治疗** ```sql -- 好习惯: -- 1. 小批量操作 -- 2. 提交前查询验证 -- 3. 关键操作加确认 -- 4. 定期备份 ``` 3. **补救措施有限** - 只能通过反向SQL、binlog或备份恢复 - 都需要额外的时间和资源
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值