下单扣库存失败回滚,商品缓存已经被删掉,下一次读请求把回滚前的旧库存回填进缓存,页面显示还能买,实际库存已经为 0。日志里能对上时间点,这种反而好排。

删缓存写在事务方法内部,事务回滚不会撤销这次删除。缓存被删后产生的读请求,读到的还是未提交前的旧数据,又被写回缓存。这一点先确认清楚,后面就不用反复试。

TransactionSynchronizationManager.registerSynchronization(
  new TransactionSynchronization() {
    public void afterCommit() { cache.invalidate(key); }
  });

「事务回滚删缓存」排查到最后往往是很小的一处差异,前面那些复杂猜测可以先放一放。偶发问题先统计频率,一小时几次和一天一次,查法完全不同。

改完顺手把文档补一句,省得下次自己重新推一遍。

处理上按这个顺序:删除动作放到 afterCommit 里 事务成功才执行;失败场景用延迟双删 隔几百毫秒再删一次;缓存值带库存版本 回填时版本旧的拒绝写入。

结果对不对很好判断,制造一次库存回滚,缓存没有被提前删除,页面显示的库存与数据库一致。

作者 9823189