入账

实现方式一:

入账需要什么参数呢?

1,付款方账号。2,收款方账号。3,金额(发生额)。4,资金变动方向(增加,减少)。5,业务订单号。

需不需要记录一些调用者信息呢?

嗯,账户与业务别太强关联了。这些东西交给账务系统吧。

A.为了控制并发,获取分布式锁。(tryLock)

细节:分布式锁的key是收款方账号加一个随机整数数字(通过Random.nextInt()生成,可以配置,目前是10)。也就是说并发控制是按照收款方账户的维度和一个随机数字控制的,锁的超时时间也是这个随机数字。

B.校验金额为正数。

C.保存交易流水,流水号是唯一主键,所以起到去重,防止重复入账的功能。(有一个独立的交易流水表)

D.根据收款方账户查账户,采用FOR UPDATE WITH RS的方式,进行行锁。

E.校验收款方账户的状态。(非冻结啊什么的。根本就没有付款方账户什么事啊,难道因为参数要统一?)

F.校验当前账户余额与数字签名是否合法。(Base64加密,保证金额不能被篡改)

G.判断当前日期,如果当前交易日与上一个交易日字段(这是个字段)里存的值不同(不是同一天),则更新上一交易日余额与上一交易日。

H.增加当前账户余额并根据金额生成签名。

I.检查账户中各种额度与当前账户余额的关系。保证各种额度不大于当前账户余额。

J.保存账户历史。

K.保存账户快照。

L.保存新的当前账户余额。

疑问点:

1. A部分的分布式锁的key,只用收款方账号好理解,加上一个随机数字能好好的控制并发吗?

解答:呃,其实对入账交易而言,真正控制并发的是数据库层面。采用了乐观锁(version)和select for update两种方式同时加锁来保证数据的准确性。所以这个redisLock其实类似一个连接池的概念。可以通过配置来控制同时最多有几个请求同时操作一个账户。避免针对某一个收款方账户的入账操作过多,占用过多资源。

2. B部分,其实保存完交易流水号就可以放开分布式锁了,对吧。锁最小粒度原则。

解答:不是为了控制并发,是为了控制同时访问数量。所以~

实现方式二:

 A.创建redisLock,key是请求流水号(全局唯一)。此处redisLock用来做并发控制。

B.创建第二个redisLock,key是账户ID。超时时间6秒,tryLock 5秒。

Lock lock = Locks.getRedisLock(Locks.ACCOUNT_LOCK_KEY+ command.getAccountId(),
Configs.getConfig(Configs.MERCHANT_ACCOUNT_SINGLE_LOCK_TIME, 6));
try {
if (lock.tryLock(Configs.getConfig(Configs.SINGLE_LOCK_RETRY_TIME, 5))) {
Future<?> future = executor.submit(new Runnable() {
@Override
public void run() {
command.exe(accountService);
}
});
future.get(Configs.getConfig(Configs.THREAD_POOL_TIME_OUT, 10), TimeUnit.SECONDS);
} else {
throw MerchantAccountException.ACCOUNT_LOCK_FAIL.newInstance("获取不到锁,lockKey:{0}",
Locks.ACCOUNT_LOCK_KEY_PRE + command.getAccountId());
}
} finally {
lock.unlock();
}

小伙伴们认为,这个多线程是多余的,然后这个redis锁也是多余的,因为都是用了数据库的行锁。

但是,阅读代码发现任务最后都是交给executor这个线程池来处理的,它起到一个限流的作用,一共只有20个线程在工作。

C.开始执行入账任务,这里用到了TransactionTemplate

transactionTemplate.execute(new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(TransactionStatus status) {
}
});

这样使用事务,跟普通的注解方式有什么区别呢?

参考:https://blog.csdn.net/memery_last/article/details/54573691

D.查询账户,同样使用了行锁FOR UPDATE WITH RS。

E.针对操作对传入的参数进行校验。

F.保存交易流水和账户历史。

G.采用乐观锁更新账户余额。

H.更新余额快照。

 

 
原文地址:https://www.cnblogs.com/coolgame/p/9984268.html