开发过程中,如何确保业务的执行的完整性,一致性

水平凡 发布于 2015/10/19 15:42
阅读 679
收藏 1
PHP

MySQL连接为什么挂死了?别踩坑!>>>

比如开发一个稍微大点的系统,业务逻辑就好几层~~~

比如我们公司是一个电商网站,有个功能,结算。

结算设计如下表:

商品表:goods

商品报名表:goods_bm

会员资金日志表:members_money_logs

会员资金索引表:members_money

结算的业务过程这样的,后台结算人员,填入销量,这时系统根据销量计算相应的金额。更新到goods表里的charge_service_fees字段,同时goods_bm表对应的charge_service_fees字段也进行更新。

然后在调用扣钱的方法,扣钱的方法首先会查询members_money表,判断用户是否有足够的金钱进行支付。如果有,会往members_money_logs表里,插入一条扣款记录。然后,通过计算members_money_logs表的 加、减钱操作算出当前余额,更新到members_money这个索引表。这些都成功后,才回更新goods表中is_complete字段为1,同时goods_bm表的is_complete字段也要跟着修改,标示处理完成~

想法很好,,但是正式使用后,会遇到很多问题,比如:

1、钱扣了,goods表的is_complete字段更新失败。

2、不知道是否并发,还是其他未知原因,造成members_money_logs表重复插入一条相同记录。导致最后members_money这个索引表的结果错误。

3、goods_bm表没有被同步修改~


遇到类似的情况,大伙有啥想法没有?

第二点是最容易出现的问题

以下是问题补充:

@水平凡:扣钱的方法里,有启用事务~ (2015/10/19 16:11)
加载中
0
幻之羽翼
幻之羽翼

从查询members_money表判断用户是否有足够的金钱进行支付之后,打开事务,用innodb引擎。就算查的不对,最后扣款失败事务也会全部回滚,不会出现致命错误

0
c
chenjustin
用事务控制呀
水平凡
水平凡
事务肯定是有用的
0
聽雨人
聽雨人
我大PHP处理财务走三步:
第一,使用事务,级别为可重复读;事务保证一致性,可重复读没有脏读,不可重复读的问题,mysql通过多版本管理避免了幻读,大概是这样,我没去确认。
第二,立刻锁用户财务记录,select * from members_money where user_id=1 for update。锁住账户,避免账户并发操作,导致金额扣成负数,或少扣。
第三, 记日志,什么用户出账还是入账多少钱,对应的操作id是多少,以后查问题有用。

另外还有一条注意:
金额计算,PHP用bcmath。mysql用decimal字段。
聽雨人
聽雨人
回复 @luokery : 并不是所有财务操作都是在一个队列里面执行的,锁住账户是最保险的做法,而且只是行锁而已,在我认知的应用里,一个账户会存在并发,但同一个账户不会有大量的并发业务在等待
luokery
luokery
不赞同锁表的方法, 会造成业务大量等待吧!? 个人认为使用消息队列可行.
0
Ambitor
Ambitor

通过计算members_money_logs表的 加、减钱操作算出当前余额-------这个感觉很离谱啊。。

members_money_logs表重复插入一条相同记录----------这个要看是否时间创建都是一样的,如果是,大多数是页面没控制或者你后台没控制,到底用户点了2次?跟钱相关的东西 还是慎重的好,,

Ambitor
Ambitor
回复 @水平凡 : 应该是用户点了两次发了两次请求吧,但是如果是这样的话,应该整个消费都有两次哦,你可以根据你的代码 仔细分析分析
Ambitor
Ambitor
回复 @水平凡 : 我觉得发生交易的时候就应该去member_money表读取当前余额,然后完成交易的时候就减去当前消费就好,为啥要去计算日志表,日志就是用来记录操作的,咋跟余额的业务搞一起去了呢,至于应用 可以在扣钱的方法加上lock操作,locak条件就是userId,单机就这么简单,集群的话就利用redis这种东西 做一个锁池。
水平凡
水平凡
重复插入的那个是时间间隔一秒插入的~~
水平凡
水平凡
我也感觉很离谱,你有啥推荐的方案?
0
流氓兔_
流氓兔_
<?php

class {
public function __construct(){
}
}



返回顶部
顶部