(高并发)防止重复点击,屏蔽多次无效请求的解决方案(优惠劵被重复领取,恶意撸羊毛)
程序员文章站
2022-07-11 11:23:41
java,控制高并发下重复点击,多次多余请求,redis互斥锁 ......
一、问题描述:
单应用切换至分布式,优惠劵被同一时间同一优惠劵领取多张,比如使用模拟器1s内请求1000次,可能被领取100张。
以前插入前先查询是否存在,无法有效解决,还是会被撸羊毛。
二、解决方法:
1.app前端增加控制,(比如按钮点击后失效);
2.利用数据库层的事务处理,比如:插入的同时查询是否存在,利用数据库自身的事务管理,同一sql实现
insert into buyer_collect(buyer_id,goods_id,create_time)
select #{userid},#{goodsid},now()
from dual where not exists(select 1 from buyer_collect where buyer_id = #{userid} and goods_id = #{goodsid})
3.redis互斥锁(个人推荐,复用性好,稳定性好)
如果框架还未整合redis请自行查阅处理,这边直接上解决方案:引入jar包,本人使用2.9
<dependency>
<groupid>redis.clients</groupid>
<artifactid>jedis</artifactid>
</dependency>
利用jedis类的set方法特性
nxxx的值只能取nx或者xx,如果取nx,则只有当key不存在是才进行set,如果取xx,则只有当key已经存在时才进行set
expx的值只能取ex或者px,代表数据过期时间的单位,ex代表秒,px代表毫秒。
time 过期时间,单位是expx所代表的单位。
public string set(string key, string value, string nxxx, string expx, int time) {
this.checkisinmultiorpipeline();
this.client.set(key, value, nxxx, expx, time);
return this.client.getstatuscodereply();
}
编写公共方法,可根据自己的实际情况自行改造,本用例来源于网络,较为成熟稳定(亲测可行)
1 private static final string lock_success = "ok"; 2 private static final string set_if_not_exist = "nx"; 3 private static final string set_with_expire_time = "ex"; 4 5 /** 6 * 获取分布式锁 7 * @param lockkey 锁 8 * @param requestid 请求标识 9 * @param expiretime 超期时间 10 * @return 是否获取成功 11 */ 12 public boolean trygetdistributedlock(string lockkey, string requestid, int expiretime) { 13 jedis jedis = null; 14 try { 15 jedis = getjedis();
16 string result = jedis.set(lockkey, requestid, set_if_not_exist, set_with_expire_time, expiretime); 17 if (lock_success.equals(result)) { 18 return true; 19 } 20 return false; 21 } finally { 22 returnresource(jedis); 23 } 24 }
//redis缓存 5s内重复请求无效
boolean result = null;
string key = "项目名称+功能模块" + userid + couponid;
string requestid = uuid.randomuuid().tostring();
try {
//获取分布式锁
result = rediscacheservice.trygetdistributedlock(key, requestid, 5);
}catch (exception e){
return new jsonresult(jsonresultcode.failure,"连接redis取数异常","");
}
if(!result){
return new jsonresult(jsonresultcode.failure,"请勿频繁点击!","");
}
附上使用的一小段代码,希望能秒懂解决实际问题
userid :用户id
couponid :优惠劵id
项目名称+功能模块:根据自己项目命名
结合自己项目框架自行修改,一次编写,复用性好。有效解决项目中类型的问题
上一篇: 越是高级的饭店,吃饭的人越不懂节约
下一篇: 爬虫学习之第四章爬虫进阶之多线程爬虫