2021-03-07 00:03:24
答案:本次线上事故的核心问题是事务未正确提交导致数据不一致,具体表现为转账扣款成功但收款未更新。根本原因包括异常处理遗漏、连接未释放及部分提交风险。以下是详细分析与解决方案:
问题根源分析异常未正确捕获
若 addBalance() 方法抛出异常(如数据库约束冲突),catch 块会触发回滚,但若异常未被捕获(如非 Exception 类型的错误),rollback() 可能失效,导致扣款已提交而收款未执行。
连接未释放
若 conn.close() 前发生异常(如网络中断),连接未归还连接池,可能引发连接泄漏,进而阻塞后续请求。
部分提交风险
在极端情况下(如 commit() 执行前连接断开),数据库可能已提交扣款操作(因某些数据库的隐式提交机制),但收款操作未执行,导致数据不一致。
通过 Spring 的 @Transactional 注解实现自动事务管理,避免手动控制遗漏:
@Transactional(rollbackFor = Exception.class)public void transfer(String fromUser, String toUser, BigDecimal amount) { accountMapper.deductBalance(fromUser, amount); accountMapper.addBalance(toUser, amount);}优势:
注意事项:
直接使用 SQL 事务保证原子性:
START TRANSACTION;UPDATE account SET balance = balance - 1000 WHERE user_id = 'A';UPDATE account SET balance = balance + 1000 WHERE user_id = 'B';COMMIT;适用场景:
使用 Druid 等工具配置 removeAbandoned 参数,自动回收泄漏连接。
嵌套事务需明确指定 Propagation.REQUIRED(加入当前事务)或 REQUIRES_NEW(新建事务)。
监控事务执行时间,对超时事务触发告警。
金融级系统需严格保证事务的原子性与持久性。推荐优先使用 Spring 声明式事务或数据库原子操作,避免手动管理漏洞。同时,需结合连接池监控、超时控制等手段提升系统稳定性。
互动话题: 你是否遇到过类似“幽灵数据”问题?欢迎分享排查经验!