蚂蚁金服社招笔试——根据需求实现一个转账接口

最近在考虑换工作,经历了两轮电话面试之后,蚂蚁金服给我发了一份笔试题目,需求如下:

使用java语言编写, 实现一个转账接口. 该接口提供账户之间的转账服务,入参包括转入账号、转出账号,交易金额,以及交易单号,接口返回是否处理成功, 以及失败原因。请确保在并发请求下, 资金处理期间和最终, 用户的账户余额都不会透支,同一笔交易单不会被重复处理。不需要编写UI界面. 不需要连接数据库,数据库操作在内存中模拟即可。

简单分析需求之后,就开始撸代码了。代码实现以上传到码云上:代码地址

这里就简单的说一下,自己分析过程。

1. 对于支付相关的接口,必须保证其幂等性,即相同参数的转账请求,返回结构必须相同,统一笔交易只能执行一次转账,有关接口幂等性实现可以参考:相关支付业务测试中如何保证幂等性

2. 转账过程(A账户向B账户转账)需要在一个事务里

3. 为了保证在并发情况下,同一时刻只允许一个线程操作转账过程中涉及到的账户,但是其他账户可以被其他线程操作, 因此选择数据的行锁(Mysql InnoDB行锁 for update实现) 

4. 在并发情况下,转账事务可能会造成死锁,

可能出现死锁的原因是,并发情况下对两个账户的操作无法保证其执行顺序

线程一执行的是:【账户A】给【账户B】转账
线程二执行的是:【账户B】给【账户A】转账

如果两个转账动作同时执行,则会出现
线程一会请求对【账户B】进行加锁,线程二会请求对【账户A】进行加锁
由于此时的【账户A】已由线程一进行锁定,【账户B】已由线程二进行锁定
此时就会产生死锁问题。

通过上面的问题描述可以发现,在一个转账的过程中【账户A】、【账户B】的执行是有序的
但是在多个转账过程中【账户A】、【账户B】的执行是无序的。
因此只要保证每次执行转账时对账户的操作按照顺序执行就可以避免死锁

例如在系统中对所有的账户进行排序:
【账户A】、【账户B】、【账户C】、【账户D】、【账户E】、【账户F】

线程一执行【账户A】给【账户B】转账逻辑:
1. 开启事务
2. 【账户A】的余额减去
3. 【账户B】的余额增加
4. 提交事务

线程二执行【账户B】给【账户A】转账逻辑:
1. 开启事务
2. 【账户A】的余额增加
3. 【账户B】的余额减去
4. 提交事务

将账户进行排序,保证转账过程中【账户A】始终先于【账户B】,这样就可以避免产生死锁问题。

解决方案:账户表中添加自增id字段,用于账户排序 id小的先执行,解决的方法很多

猜你喜欢

转载自blog.csdn.net/shallynever/article/details/81271489