关于原子性:第三方支付平台提现原子性问题解决方案
在业务逻辑中,常常会碰到提现需要。提现的实现个别分为两个步骤: 扣除余额调用第三方领取接口进行提现(比方微信领取:企业付款到零钱)假如咱们这样写(伪代码): <?phpDB::beginTransaction();try { $member = Member::find($id); $member->money -= $withdrawMoney; $member->save(); $wechat->payment->pay($openid, $withdrawMoney); DB::commit();} catch (\Exception $e) { DB::rollback(); Log::error($e->getMessage());}这样写会有什么问题?当执行commit的时候,因为网络起因,数据库忽然连不上了或者数据库挂了,怎么办?会导致什么结果? 会导致钱付出去了,然而余额没扣。 还有同学可能会有其它疑难,如果数据库操作胜利,接口调用因为网络起因失败了,会怎么样?就咱们下面这段代码而言,如果接口调用失败,并且调用失败后会抛出异样的话,那就会被catch到,try外面甚至都走不到commit,间接rollback了。所以接口调用失败时,不会有原子性问题。怎么样保障提现操作是原子性的,要么扣余额和调接口同时胜利,要么同时失败? 把调微信接口的操作,转化成一个异步工作。 <?phpclass WechatWithdrawJob{ public static function withdraw($openid, $money) { $result = $wechat->payment->pay($openid, $money); if ($result->return_msg == 'SUCCESS') { return true; } return false; }}<?phpDB::beginTransaction();try { $member = Member::find($id); $member->money -= $withdrawMoney; $member->save(); $task = new Task; $task->callback = json_encode([WechatWithdrawJob::class, 'withdraw']); $task->params = json_encode([$openid, $withdrawMoney]); $task->add_time = time(); $task->save(); DB::commit();} catch (\Exception $e) { DB::rollback(); Log::error($e->getMessage());}起一个异步工作生产过程,不停地轮询生产。 ...