面试官扎心一问:防止重复请求提交,有什么方案?

背景

在日常开发中,咱们常常会面对防止重复请求的问题。当服务端对于请求的响应涉及数据的修改,或状态的变动时,可能会形成极大的危害。重复请求的后果在交易系统、售后维权,以及支付系统中尤为严重。可是不少时候,都是期望着前端来限制,好比提交以后,按钮diseabled之类的,其实这些都是不靠谱的。关键时候仍是须要后端来校验。前端

解决方式

一、基于缓存数据状态的验证

Redis存储查询轻量快速。在request进来的时候,能够先记录在缓存中。后续进来的request每次进行验证。整个流程处理完成,清除缓存。redis

  if (!CacheExtension.getInstance().AddUnique($"{key}_unique", 1, DateTimeOffset.Now.AddDays(365)))
            {
                LogExtention.getInstance().WriteCustomLogAsync("", "", true, "上批次还未执行结束");
                return ResponseResult.FromError("上批次还未执行结束!");
            }
 if (!string.IsNullOrEmpty(uniqueKey))
            {
                CacheExtension.getInstance().Remove(uniqueKey);
            }
            return ResponseResult.Ok();

 

二、利用惟一索引机制的验证

须要原子性操做,想到了数据库的惟一索引。新建一个表,每次request进来则往表里面插入数据, 操做完成后,删除此条记录。shell

 

 

 

三、基于缓存的计数器验证

因为数据库的操做比较消耗性能,了解到redis的计数器也是原子性操做。果断采用计数器。既能够提升性能,还不用存储,并且能提高qps的峰值。 每次request进来则新建一个以orderId为key的计数器,而后+1。若是>1(不能得到锁): 说明有操做在进行,删除。若是=1(得到锁): 能够操做。数据库

redis> SET test 20
OK
redis> INCR test
(integer) 21
redis> GET test # 数字值在 Redis 中以字符串的形式保存
"21"

//获取指定的全部计数器
HGETALL counter:user:{userID}   

//获取指定的指定计数器
HMGET counter:user:{userID}  praiseCnt hostCnt 

//指定点赞数+1
HINCRBY counter:user:{userID}   praiseCnt

 


总结

一、c#自己有lock机制,单体模式能够使用。

二、可是考虑到咱们的分布式部署,建议仍是用缓存。在大并发的状况下,程序各类状况的发生。特别是涉及到金额操做。因此在大并发要互斥的状况下能够考虑二、3两种方案。

相关文章
相关标签/搜索