Spring引用Redis分布式锁

1.redis的两个命令:SETNX 、GETSET

在学习分布式锁之前,首先需要了解一下redis的两个命令:setnx和getset

setnx:设置一个键值对到redis,若redis中已经存在,则无法再次设置进去 getset:获取redis中的一个值得同时设置一个值进去

2.根据setnx和getset的原理,设置对应的分布式锁,代码如下:

 private <T> T execute(Function<ShardedJedis, T> function) {
        ShardedJedis shardedJedis = null;
        try {
            // 从连接池中获取到jedis分片对象
            shardedJedis = shardedJedisPool.getResource();
            return function.execute(shardedJedis);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != shardedJedis) {
                // 关闭,检测连接是否有效,有效则放回到连接池中,无效则重置状态
                shardedJedis.close();
            }
        }
        return null;
    }
//获取锁 name对应锁的key  value对应过期时间 这里也可以设置redis中数据的过期时间
public boolean getLock(final String name,final String value){
	return this.execute(new Function<ShardedJedis, Boolean>() {
        [@Override](https://my.oschina.net/u/1162528)
        public Boolean execute(ShardedJedis shardedJedis) {
        	Long setnx = shardedJedis.setnx(name, value);
        	if(setnx==1L){
        		return true;
        	}
        	String oldTimeValue = shardedJedis.get(name);
        	if(StringUtils.isNotEmpty(oldTimeValue) && System.currentTimeMillis()>Long.valueOf(oldTimeValue)){
        		String oldTime = shardedJedis.getSet(name,value);
        		if(StringUtils.isNotEmpty(oldTime)&& oldTime.equals(oldTimeValue)){
        			return true;
        		}
        	}
        	return false;
        }
    });
}
//解锁 name对应锁的key  value对应过期时间 这里也可以设置redis中数据的过期时间
public void unLock(final String name,final String value){
	this.execute(new Function<ShardedJedis, Boolean>() {
        [@Override](https://my.oschina.net/u/1162528)
        public Boolean execute(ShardedJedis shardedJedis) {
        	if(StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(value)){
        		String timeValue = shardedJedis.get(name);
        		if(StringUtils.isNotEmpty(timeValue)&& timeValue.equals(value)){
        			shardedJedis.del(name);
        			return true;
        		}
        	}
			return false;
        }
	});
}

然后就可以在程序中使用了:

 public  void exportStudentSubmitExperimentFileReport(HttpServletResponse response,HttpServletRequest request,Integer[] ids,TeacherInfo teacher) throws Exception{
    	//这里拿锁的时间
    	String value = String.valueOf(System.currentTimeMillis()+lock_due_time);
    	//这里我循环拿锁15次,拿不到就报错
    	for(int i=1;i<15;i++){
    		//这里 拿到锁就执行,拿不到锁就循环
    		if(redisLock.getLock(exportExperimentReport, value)){
        		List<SubmitExperimentFile> list=	submitExperimentFileMapper.selectsubmitExperimentFileByIds(ids);
            	List<Map<String, Object>> listMap = this.toHtml(list);
            	if(listMap!=null && listMap.size()>0){
            		
            		if(listMap.size()==1){
            			Html2WorldUtils.html2WorldList(request, response,listMap.get(0));
            		}else{
            			Html2WorldUtils.html2WorldList(request, response, listMap,FILE_PATH+VS_EXPERIMENT+"/experiment_reports/"+teacher.getName(),"实验报告");
            		}
            	}
            	updateExportStatusByIds(ids,1);
            	//解锁
            	redisLock.unLock(exportExperimentReport, value);
            	break;
        	}
    		if(i>=14){
    			throw new RuntimeException("导出实验报告的教师过多,请稍后重试");
    		}
    	}
    }

注意:加锁了之后要记得解锁

猜你喜欢

转载自my.oschina.net/u/3361262/blog/1583477