实际项目中 资源竞争,加锁 redis setnx 具体解决方案

一.概念

资源竞争:多个用户同时访问同一个资源。

eg:理想情况下,顾客A去买车票,提交订单并付款,付款成功后修改该票状态,由待出售改为已出售,这时其他用户买票,系统查询待出售票就不会查到该票。
如果系统中用户较多,多个用户同时购买同一张待出售的票,如果不做处理,就会出现,多个用户都付款成功。但资源只有一个,这显然是有问题的

加锁:给资源加锁,并发变成串行,多个用户不能同时访问,只有等一个用户访问完了下一个用户才能进入。

结论:
1.资源竞争问题和用系统用户量有关,用户量较大才可能出现,测试阶段不会发现。
2.所有涉及到资源竞争 的地方都必须加锁

二.redis setnx解决方案

原理:调用redis setnx方法,该方法具有原子性,可以保证串行。
功能:多个用户同时访问同一个资源,使用redis底层提供的setnx方法,将并发改为串行。程序对第一个抢到该资源的用户加锁,加锁后拦截其他用户获得该资源,并且当前用户可以正常访问。加锁后如果用户一直不付款,设置30分钟后释放锁

		/*
		*固定字符串+资源id作为key,用户id作为值,设置过期时间为30分钟(RedisUtil封装的setnx()方法,已贴出)
		*redis中key存在,返回false;否则,true
		*用户id作为值,避免当前用户也被锁住
		*/
		boolean flag = RedisUtil.setnx(WebConstatVar.IP_RESOURCE_ID_ + splitIds[i], userId.toString(), 30 * 60);
		if(!flag) {
			String _userId = RedisUtil.get(WebConstatVar.IP_RESOURCE_ID_ + splitIds[i]);
			//key取值,和userId比较,判断资源是否被当前用户占用。
			if(StringUtils.isNotEmpty(_userId)&&(!_userId.equals(userId.toString()))){
				IpResources ipResources = ipResourcesService.findIpResources(Integer.valueOf(splitIds[i]));
				String usedIp = ipResources.getIntranetIp() + "-" + ipResources.getInternetIp();
				responseData.setStatus(ResponseData.STATUS_ERROR);
				responseData.setMessage("支付失败,资源为:" + usedIp + "的ip已被其他用户先申请");
				return responseData;
			}
		}


/*RedisUtils类中封装redis提供的setnx方法
*seconds:缓存过期时间
*key存在,返回false;key不存在,返回true
*/
public static boolean setnx(String key,String value, int seconds) {
		ShardedJedis shardedJedis = null;
		try {
			shardedJedis = getShardedJedisPool();
			//setnx的含义就是SET if Not Exists,其主要有两个参数 setnx(key, value)。
			//该方法是原子的,如果key不存在,则设置当前key成功,返回1;如果当前key已经存在,则设置当前key失败,返回0。
			long result = shardedJedis.setnx(key, value);
			shardedJedis.expire(key, seconds);
			return result == 1;
		} catch (JedisConnectionException e) {
			try {
				releaseBroken(shardedJedis);
			} catch (Exception ex) {
				log.error(ex.toString());
			}
		} catch (Exception e) {
			log.error(e.toString());
		} finally {
			try {
				release(shardedJedis);
			} catch (Exception e) {
				log.error(e.toString());
			}
		}
		return false;

	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值