业务流程
对于一个融资标的invest表, 标的id,标的总融资金额(total_money), 已投资金额(invested_money),满标时间(finish_invest_time),标的状态(status)
假如有多个用户user同时投标,投资金额为M, 为保证数据一致性,以下步聚在同一个事务当中
1. 查询left = total_money - invested_money, 如果left <=0, 则不可投, 如果M > left, 则提示投资金额不能大于剩余可投金额
2. 查询用户资金余额balance, 如果balance<M, 则提示用户账户余额不足请先充值
3. int rows = update user表set balance = balance - M where id = ? and balance - M >=0,如果rows=0,则回滚
4. 插入记录到已投资列表表中insert into invest_list表
5. int rows = update invest表 set invested_money = invested_money + M where id = ? and invested_money + M <= total_money, 如果rows=0则事务回滚
6. 查询left = total_money - invested_money,如果left=0,则更改状态status为'还款中',满标时间为当前时间
7.给用户发送短信或邮件提示投标成功
如果按照此事务流程,系统最容易堵塞在步骤5中,系统的并发度比较低, 所以计划采用异步队列的方式
将标的id,和可投资金额left=total_money - invested_money保存在内存ConcurrentHashMap中, 当用户投资金额M时, left = left - M,如果left> 0时,表示可投,则分出一个线程并在同一个事务中用来执行如下操作
1. 查询用户资金余额balance, 如果balance<M, 则提示用户账户余额不足请先充值,并将map中left加回M
2. int rows = update user表set balance = balance - M where id = ? and balance - M >=0,如果rows=0,则回滚并将map中left加回M
3. 插入记录到已投资列表表中insert into invest_list表,并将该用户投资记录放到一个queue中去
4. 从queue中取出该用户投资记录,并异步执行上一个事务的5、6、7步聚
总结, 想方设法将单事务任务转变成多线程任务来执行, 使用消息队列来达到最终一致性