@yanglfyangl
2018-07-31T07:45:14.000000Z
字数 3395
阅读 396
可能出现的问题:
1 . 数据可能被篡改。
1. 如果接口中直接传钱数,就可能在某种情况下被截获和修改。
2. 或本来不属于某个用户的订单,因为被截获,导致TA来支付,导致的一系列问题。
2 . 接口不幂等,重复扣/加钱或豆。
1. 比如扣款请求已经被服务器端正确处理,但服务器端的返回结果由于网络等原因被掉丢了,导致客户端无法得知处理结果。这时候客户端重试了,导致了扣款两次。
2. 如果流程更长,特别是有写统计数据的地方(比如总钱数,当前可用钱数。。。),也容易造成类似的问题。
3 . 状态不同步/消息不一致造成的各种问题。
1. 比如因为网络原因,服务A没有把支付完成的消息实时反馈给服务B。
2. 或服务器A通知了,但服务器B处理失败了。
3. 最复杂的是服务A发了消息,成功了。但因为网络原因他不知道,以为发送失败了,又做了重试。
当然,还有“安全风控等一系列问题,但因为更多的是产品逻辑上的,在这里不多说了”
需要在开发中注意的地方
防数据篡改:
1. 以订单ID为参数,尽量避免钱数或其它信息做为参数,给外界系统以更改的机会。
2. 更加严格的参数校验,比如订单与用户的关系,订单状态。。。
3. 加风控。。。
幂等:
1. 每个可能更改数据的地方,都需要用幂等保护起来,同一个“事件”的数据处理,只执行一次。
状态不同步:
1. 消息发送失败时要支持重试。(但前提是一定要消息消费方保证幂等)
2. 消息服务器如果出问题,需要有相应的补偿机制。
3. 接口层发消息的同时,也要支持拉取消息。
当然,这也就要求了在写代码之前,要想清楚
1. 到底是TCC?
2. 还是最终一致性?
3. 还是全不走,但能提供各种业务补偿来去支持失败?
每种做法都会导致代码结构和量级很不一样,所以这些需要提前设计好。
与社交相关的数据库表:
1. 账户表
2. 圈子账户表
3. 平台账户表
4. 账户银行卡对应表
5. 账户流水表
6. 账户盈豆表
7. 盈豆奖励明细表
8. 盈豆交易变动流水
9. 账户赢币表
10. 账户赢币奖励明细表
11. 盈币交易变动流水
还有几张与社交无关的
1. SBU-账户
2. 账户-供应商
3. 生豆交易变动流水
4. 账户生豆奖励明细表
5. 账户生豆表
。。。
在有些表中,有些数据是“计算”的数据(相对容易出现不一致和不幂等的部分)
USABLE_BEANS DECIMAL(20, 4) COMMENT '生豆余额',
FREEZE_BEANS DECIMAL(20, 4) COMMENT '冻结余额',
UNCLEARED_BEANS DECIMAL(20, 4) COMMENT '未清算余额',
PROFIT_BEANS DECIMAL(20, 4) COMMENT '收益豆',
查询条件比较复杂,目前看分片分库分表等都不容易处理。未来的查询是个问题。
AccountBlanceWithdrawalProvide 中
@Override
public Response<BalanceWithdrawalVo> withdrawal(Request<BalanceWithdrawalDto> req) {
BalanceWithdrawalDto dto = req.getData();
LogMgr.error("*********余额提现*******参数:"+FastJsonUtil.parseToJSON(req.getData()));
。。。
。。。
try {
//校验
Response<Integer> validateRes = withdrawalValidate(dto);
if(!validateRes.isSuccess()) {
response.failure(validateRes.getErrorCode(), validateRes.getErrorMsg());
return response;
}
...
accountBlanceWithdrawalService.insert(entity);
LogMgr.sysInfo(dto.getmId()+"*********************余额提现记录插入成功**********************"+FastJsonUtil.parseToJSON(entity));
// 返回结果封装start
LogMgr.sysInfo(dto.getmId()+"*********************余额提现**********************"+FastJsonUtil.parseToJSON(dto));
。。。
。。。
//插入订单
PayOrder order = new PayOrder();
。。。
。。。
payOrderService.save(order);
//插入订单
// 保存到数据库
LogMgr.error(dto.getmId()+"*********余额提现*******返回:"+FastJsonUtil.parseToJSON(response));
}catch(Exception e) {
LogMgr.error("*********余额提现*******异常:"+e.getMessage(),e);
response.failure("500",e.getMessage());
}
return response;
}
这个代码中,有这样几个问题
这样的代码还是挺多的存在于目前的支付中的。
。。。。。。。
}
//事务性消息通知结成功
JSONObject jsonObject = new JSONObject();
jsonObject.put("businessId", frozenAccountDto.getBusinessId());
jsonObject.put("businessType", frozenAccountDto.getBusinessType());
jsonObject.put("amount", frozenRecord.getAmount().toString());
jsonObject.put("channel", frozenAccountDto.getChannel());
SendResult sendFrozenBalance = payNotifyProductor.sendFrozenBalance("frozenBalance", jsonObject.toJSONString(), frozenRecord.getBusinessType());
LogMgr.sysInfo("PayFrozenThaw.provide:frozenBalance:发送MQ",FastJsonUtil.parseToJSON(sendFrozenBalance));
}catch (Exception e) {
res.setErrorCode(ResponseConstant.BASE_SERVICE_ERROR_CODE);
res.setErrorMsg(ResponseConstant.map.get(ResponseConstant.BASE_SERVICE_ERROR_CODE));
LogMgr.sysInfo("PayConsolidate.provide:payUseFrozenBalance:出参",FastJsonUtil.parseToJSON(req));
return res;
}finally {
try {
distributedLock.unLock(lockKey.toString());
}catch (CacheException e) {
LogMgr.error("payUseFrozenBalance>>>请求解锁失败>>>>>>>>>>>>>>>>>>>>解锁失败-解锁失败e:{}",e);
}
}
这代码中注释虽然写的是“事务性消息”,但消息的出错处理没有,也不能抛出异常。。。所以。。。