Redis实现分布式锁的作用和意义,可以参考这篇文章:https://zhuanlan.zhihu.com/p/268290754
代码的话,不废话,直接看我在项目中用的。 一.配置RedisTemplate对象 我是基于RedisTemplate对象来实现分布式锁的,而不是jedis。
package com.wuyouhu.common.redis.configure;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport
{
@Bean
@SuppressWarnings(value = { "unchecked", "rawtypes", "deprecation" })
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
{
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
template.setValueSerializer(serializer);
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
}
二.redis分布式锁Entity类
package com.wuyouhu.common.redis.domian;
public class RedisLockEntity {
private String lockKey;
private String requestId;
public RedisLockEntity() {
}
public String getLockKey() {
return lockKey;
}
public void setLockKey(String lockKey) {
this.lockKey = lockKey;
}
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
@Override
public String toString() {
return "RedisLockEntity{" +
"lockKey='" + lockKey + '\'' +
", requestId='" + requestId + '\'' +
'}';
}
}
三.lua解锁脚本代码 放在模块的resources目录下。
if redis.call('get',KEYS[1]) == ARGV[1] then
return redis.call('del',KEYS[1])
else
return 0
end
四.redis分布式锁工具类
package com.wuyouhu.common.redis.service;
import java.util.*;
import java.util.concurrent.TimeUnit;
import com.wuyouhu.common.redis.domian.RedisLockEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
public class RedisService
{
private final static Logger logger = LoggerFactory
.getLogger(RedisService.class);
@Autowired
public RedisTemplate redisTemplate;
public boolean lock(RedisLockEntity redisLockEntity) {
boolean locked = false;
int tryCount = 3;
while (!locked && tryCount > 0) {
locked = redisTemplate.opsForValue().setIfAbsent(redisLockEntity.getLockKey(), redisLockEntity.getRequestId(), 2, TimeUnit.MINUTES);
tryCount--;
try {
Thread.sleep(300);
} catch (InterruptedException e) {
logger.error("线程被中断" + Thread.currentThread().getId(),e);
}
}
return locked;
}
public boolean unlock(RedisLockEntity redisLockEntity) {
if (redisLockEntity == null || redisLockEntity.getLockKey() == null || redisLockEntity.getRequestId() == null)
return false;
boolean releaseLock = false;
String requestId = (String) redisTemplate.opsForValue().get(redisLockEntity.getLockKey());
if (redisLockEntity.getRequestId().equals(requestId)) {
releaseLock = redisTemplate.delete(redisLockEntity.getLockKey());
}
return releaseLock;
}
public boolean unlockLua(RedisLockEntity redisLockEntity) {
if (redisLockEntity == null || redisLockEntity.getLockKey() == null || redisLockEntity.getRequestId() == null)
return false;
DefaultRedisScript<Long> redisScript = new DefaultRedisScript();
redisScript.setLocation(new ClassPathResource("unlock.lua"));
redisScript.setResultType(Long.class);
Object result = redisTemplate.execute(redisScript, Arrays.asList(redisLockEntity.getLockKey()), redisLockEntity.getRequestId());
return result.equals(Long.valueOf(1));
}
}
五.分布式锁业务使用示例
package com.wuyouhu.templates.controller;
import com.wuyouhu.common.redis.domian.RedisLockEntity;
import com.wuyouhu.common.redis.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/seat")
public class SeatController extends BaseController {
@Autowired
private RedisService redisService;
@GetMapping(value = "/testRedisLock")
public String testRedislock1() {
System.out.println("start....lock");
RedisLockEntity redisLockEntity = new RedisLockEntity();
redisLockEntity.setLockKey("lockkey");
redisLockEntity.setRequestId("1");
boolean lock = redisService.lock(redisLockEntity);
if (lock){
System.out.println("lock success!");
this.testRedisUnlock2()
} else {
System.out.println("lock fail!");
}
System.out.println("end.....lock");
return "success";
}
public String testRedisUnlock2() {
System.out.println("start....unlock");
RedisLockEntity redisLockEntity = new RedisLockEntity();
redisLockEntity.setLockKey("lockkey");
redisLockEntity.setRequestId("1");
boolean unlock = redisService.unlockLua(redisLockEntity);
if (unlock){
System.out.println("unlock success!");
} else {
System.out.println("unlock fail!");
}
System.out.println("end....unlock");
return "success";
}
}
|