在 MongoDB 上模拟事务操做来实现支付

[ 玩转 LeanCloud ] 开发者经验分享:后端

做者:Davy微信

咱们的产品叫「学海密探」,属于在线教育行业,产品须要有支付功能,然而支付最蛋疼是什么?有人会说是支付宝和微信等支付接口的接入开发!没错,但支付接口的开发算是比较简单的了,我以为凡是跟钱有关系的操做最重要的是事务问题,这一点很重要,很重要,真的很重要!LeanCloud 官方文档中有提到 MongoDB 不支持事务,并建议对事务有强烈需求的开发者使用其余折中方式来实现。咱们的支付必须用事务,咱们通过 N 轮讨后论设计了一套基于 LeanCloud 的支付场景的通用解决方案,也许其余团队比咱们作得好,在这里仍是分享下咱们的一些看法吧。并发

咱们在用户表 _User 中加入了一个 paylogs 字段,类型是 Array,主要用于存放着每一次支付日志的 id,用它来判断用户的帐户 account 的值,好比钱扣没扣,加没加等状况。由于在支付过程当中不能保证每一次操做都成功,因此还要引入一个日志表 log 来作数据的一致性,保证用户资金变更与实际相符。log 表里有一个「状态」字段 state,它的取值为 0 ~ 5,主要是从发起支付开始,生成 order 表,生成 log 表等,并记录 log 的状态,后续全部的业务都要根据 state 的状态执行不一样的业务操做,无论在哪一个状态出问题均可以根据 log表的 state 状态重复执行相应的业务操做,从而保证支付过程的数据一致性!设计

好比在充值的时候,用户扣费成功后,修改用户的 account 值成功了,但在修改 state 字段时失败了,下一次再执行时又怎么判断用户的 account 值已经改变了呢?这个问题真是过重要了,这就要用到那个 paylogs 字段,判断 paylogs 字段是否有值,有值说明刚才用户的 account 值已经操做过了,此时能够不用操做,若是没有再进行操做。这里利用了 LeanCloud 数据存储接口的按条件更新数据的功能(使用 query 参数)来保证操做的原子性,从而也解决了并发问题!这个 query 参数真得要夸一下,在 LeanCloud 还没提供这个功能以前,咱们只能采用 log 表中的新旧值比对来解决数据一致问题,但没法避免并发问题,这样当用户数据错了,咱们只能认为支付失败,而后进入人工干预环节,非常麻烦。日志

最后再说说咱们和 LeanCloud 的相遇。最初是经过朋友圈知道了 LeanCloud,后来就一直关注着。也试过一些项目,发现开发应用真是方便许多。本来大量的后端需求都要本身研发,如今都省了,只须要专一于写应用端的代码,效率天然会提升一倍以上,开发迭代速度也上去了。固然也有过顾虑,生怕遇到一些特殊场景 LeanCloud 知足不了那咱们就悲剧了!但后来看到一些知名的应用都在用 LeanCloud,内心也就安稳了,有前辈们踩过坑,有 LeanCloud 的技术支持作后盾,咱们就这样选定了 LeanCloud。接口

随着项目的进行,咱们从传统的后端服务接口开发变成了面向「Document」开发,服务端工做减轻了很多。虽然在数据设计中遇到一些复杂结构的问题,好比 Pointer 和 Relations 的问题。记得当时 Array 不支持 Pointer 的 include,因此考虑用 Relations,但在 LeanCloud 社区中又看到几个相关问题都推荐使用 Array 或者 Pointer,后来通读了相关文档对数据模型有了更深的理解,问题也就少了,因此说全面了解文档是相当重要的。事务

相关文章
相关标签/搜索