后端实习手记:MySQL事务实战进阶
|
刚进公司实习时,我以为事务就是BEGIN、COMMIT、ROLLBACK三个关键词的组合。直到第一次线上订单支付失败后出现“已扣款但未发货”的异常数据,我才真正意识到:事务不是语法糖,而是业务一致性的生命线。 导师让我排查一个库存超卖问题。代码里明明加了SELECT ... FOR UPDATE,却仍有并发请求绕过锁检查。后来发现,事务隔离级别设为READ COMMITTED,而FOR UPDATE只在当前事务内生效;若两个事务同时读取同一库存行再各自更新,后提交者会覆盖前者的修改——根本原因在于缺少唯一约束与原子扣减逻辑。我们最终改用UPDATE stock SET quantity = quantity - 1 WHERE id = ? AND quantity >= 1,并检查影响行数是否为1,把校验和更新压缩进单条语句。 一次批量导入用户数据的脚本引发死锁告警。日志显示两个事务分别按不同顺序更新user表和profile表。原来A事务先锁user再锁profile,B事务反向操作,形成环形等待。解决方式很朴素:所有涉及多表更新的业务,统一约定加锁顺序(如永远先user后profile),并在应用层用分布式锁兜底关键路径。
AI生成内容图,仅供参考 有次优化报表查询,我把一个带子查询的慢SQL改成JOIN+事务内临时表缓存中间结果。上线后发现凌晨定时任务频繁超时。查监控才发现,长事务占着undo log不释放,阻塞了其他DML操作。于是我们拆分大事务:将千万级数据处理切分为每5000条一批,每批独立提交,并在批次间加入毫秒级休眠,既避免锁竞争,又防止主从延迟飙升。 最深刻的教训来自一个“幂等补偿”设计。支付回调需先查订单状态再更新,我们用SELECT FOR UPDATE加事务保证串行,却忽略了一个边界:若事务内网络超时导致应用未收到数据库响应,重试时可能重复扣款。后来引入唯一业务流水号+INSERT IGNORE插入幂等表,把“是否已处理”的判断前置到事务最开始,用数据库唯一约束兜住逻辑漏洞。 现在写CRUD时,我会下意识问自己:这条SQL在RC和RR下行为是否一致?并发时锁范围有多大?失败回滚会不会留下脏状态?事务不是数据库的默认保护罩,而是需要主动设计的契约——它要求开发者理解隔离级别的真实代价,敬畏锁的粒度与生命周期,更要把业务规则翻译成数据库可验证的原子操作。实习三个月,我删掉了27个没加事务的update语句,也学会了在explain执行计划里找隐式锁升级的蛛丝马迹。 (编辑:云计算网_梅州站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |


浙公网安备 33038102330479号