MySQL事务控制无障碍设计实战指南
|
“MySQL事务控制无障碍设计实战指南”——半年前我把它贴在工位玻璃上,用荧光笔圈了三遍。那时正卡在支付系统跨库幂等写入的脏读问题里,线上凌晨三点告警响了七次,DBA老张盯着慢查日志说:“你这事务隔离级别设得比我家猫还高。” 我们把订单服务从MySQL 5.7升到8.0.32后,启用了SET TRANSACTION ISOLATION LEVEL REPEATABLE READ + binlog_format=ROW双保险,但订单状态流转还是偶发跳变——查了三天才发现是Spring @Transactional(propagation = REQUIRES_NEW) 和手动commit()混用,导致嵌套事务的XA分支被隐式提交。实测数据:这种组合在并发200TPS时,状态错乱率从0.37%飙到2.14%,而改用TransactionTemplate配合savepoint回滚后,错乱率归零,平均事务耗时下降43ms(P99从189ms→146ms)。 最坑的是那个“自增ID幻读陷阱”——某次灰度发现,同一笔退款单生成两条重复流水,主键ID差1000+。翻binlog发现:INSERT ... SELECT + AUTO_INCREMENT 在RR级别下会预分配ID块,但SELECT子句用了未加锁的子查询,别的事务刚好抢走了中间ID。后来我们强制在INSERT前加SELECT ... FOR UPDATE,但代价是锁等待时间峰值冲到3.8秒——于是改成UUID_SHORT() + 插入前先SELECT COUNT()检查,成功率回到99.995%,不过磁盘IO涨了17%。这事儿真没人提过,文档里只写“RR防止幻读”,闭口不谈自增列的特殊预分配机制。
文章配图,仅供参考 “MySQL事务控制无障碍设计实战指南” 新技术?对。但它不是魔法棒。上周试了MySQL 8.4的LOCK WAIT TIMEOUT=0选项配合死锁自动降级,结果压测时发现InnoDB在超时瞬间会把锁信息残留0.8秒,导致下游监听binlog的Flink作业多消费一次——查源码才知道这是lock_sys->timeout_list的延迟清理bug,补丁还在8.4.2-rc里没合入。我给它打了个主观判断:这技术像一把新刀,锋利,但刀柄还没包胶,握久了手心起泡。 2024年7月12日上线的那个库存扣减模块,我故意关掉了innodb_lock_wait_timeout的全局配置,改用每个事务开头SET innodb_lock_wait_timeout=3;结果大促时遇到极端锁争抢,237个请求在3秒内全部超时退出,但监控里只看到“业务失败”,没留任何锁堆栈——后来才想起加SHOW ENGINE INNODB STATUS\\G 到失败回调里。现在我的做法是:所有@Transactional方法必须配@Scheduled(fixedDelay = 10000)定时任务扫INFORMATION_SCHEMA.INNODB_TRX,超时就发钉钉预警。这法子笨,可管用。要真想验证这指南效果?明天下午三点,登录你们生产库,执行SELECT FROM performance_schema.events_statements_summary_by_digest WHERE DIGEST_TEXT LIKE '%BEGIN%' AND SUM_TIMER_WAIT > 3000000000000 LIMIT 5——看看前十名里有几个藏着没加WHERE的UPDATE。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

