1. Two commands of redis: SETNX, GETSET
在学习分布式锁之前,首先需要了解一下redis的两个命令:setnx和getset
setnx: set a key-value pair to redis, if it already exists in redis, it cannot be set again getset: get a value in redis and set a value in at the same time
2. According to the principle of setnx and getset, set the corresponding distributed lock, the code is as follows:
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;
}
});
}
Then you can use it in your program:
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("导出实验报告的教师过多,请稍后重试");
}
}
}
Note: Remember to unlock after locking