记一次未付款发货的天坑逻辑

前记

今天,收到一个bug fixed:用户在支付一个订单后收到N条短信提醒!

排查

因为支付只能在生成环境调试,于是远程连接服务器,找到有返回值的地方,记录返回值,然后开始测试,支付了N次没有发现一个有问题,于是问测试部门,怎么出现这个问题的!测试部门问了下用户,是因为未付款,但是卖家点了发货,听到此消息,我不禁一呆,坑能不能有个底限啊!这种逆天的逻辑怎么能出现呢!!!为啥这么说呢,接下来洒家给你详细分析。

先说下支付的逻辑:众所周知,不管是微信支付 还是 支付宝支付,都是异步进行的。也就是说用户在微信或者支付宝支付成功后,微信或者支付宝并不会第一时间把这个支付成功的消息返回给你,而是在接下来的一个小时或者更长时间内分N次给你支付成功的通知(有时候接收到第三方服务器返回success的时候还会发起多次的异步通知),所以一般业务逻辑在此处都会有一防止重复更新数据库的逻辑判断,在成功更新订单为已付款状态后,如果还收到异步通知,直接返回true。

但是因为未付款发货这种逆天逻辑的存在,在网速慢或者服务器访问量大的时候,用户支付成功,服务器未收到支付成功的异步通知,这时候,脑残卖家点了发货,并且成功了更新了数据库的订单状态,这时候,服务器收到支付成功的通知(在收到支付成功时的业务逻辑是更新未付款的订单),这时候去更新数据表,发现数据不存在(因为订单状态为已发货,而不是未付款),更坑的是,订单表的类型居然是MyISAM类型的,居然不是InnoDB类型的,如此事务完全不能进行,在发现未更新数据的时候不能rollback,这样造成了,之前成功返回异步通知的逻辑不能执行,造成微信或者支付宝异步通知一次,则更新一次数据库……

这样的逻辑简直太坑爹了!!!以此提醒同僚们:“ 程序有风险,入行需谨慎” 啊!!!

解决方案

  • 更新订单表以及订单相关表为Innodb类型(MyISAM不支持事务处理);
  • 更新响应支付通知条件,只要支付方返回支付成功通知,这边就更新为已付款状态,而不关心订单状态是否是未付款;

这种逻辑真的不要再出现了啊!!!

不说了,继续修复脏数据了……o(╯□╰)o,囧……