您的位置:首页 > 数据库 > Redis

redis锁-注解版

2020-07-18 04:12 686 查看

Redis实现分布式锁利用 SETNX 和 SETEX
基本命令主要有:
SETNX(SET If Not Exists):
当且仅当 Key 不存在时,则可以设置,否则不做任何动作。
当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0。
SETEX:
基于SETNX功能外,还可以设置超时时间,防止死锁。
项目图
代码实现
application.yml

# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=192.168.196.129
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=20
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=10
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=1000

RedisLock

/**
* @author lihaozhen
* 互斥性,安全性,可用性,对称性
*/
@Component
@Slf4j
public class RedisLock {

@Autowired
private StringRedisTemplate redisTemplate;
//设置锁的过期时间
private static final long exprise = 5000L;

/**
* @Description 加锁
*/
public boolean lock(String remark, String key, long exprise) {
if (redisTemplate.opsForValue().setIfAbsent(key, "lock", exprise, TimeUnit.MILLISECONDS)) {
log.info("loger加锁:" + remark + "-" + key);
//            System.out.println("loger加锁:" + remark + "-" + key);
return true;
}
log.error("加锁失败!");
return false;
}

/**
* @Description 释放锁
*/
public void unlock(String remark, String key) {
redisTemplate.delete(key);
System.out.println("logger释放锁了:" + remark + ":" + key);
}
}

RedisLockAnn

import java.lang.annotation.*;

/**
* @author lihaozhen
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface RedisLockAnn {
String menthodName() default "";
long  expireTime() default 5000L;
}

RedisLockAspect

/**
* @author lihaozhen
* @title: RedisLockAspect
*/
@Aspect
@Component
@Slf4j
public class RedisLockAspect {

@Autowired(required = false)
private HttpServletRequest request;

@Autowired
RedisLock redisLock;

Logger logger;

@Pointcut("@annotation(com.example.demo.lock.RedisLockAnn)")
public void redisLockAnnotation() {
}

@Around(value = "redisLockAnnotation()")
public Object methodsAnnotationWithRedisLock(final ProceedingJoinPoint joinPoint) throws Throwable {
Object re = null;
MethodSignature sign = (MethodSignature) joinPoint.getSignature();
Method method = sign.getMethod();
String key = method.getName();
long expireTime = method.getAnnotation(RedisLockAnn.class).expireTime();
if (!"".equals(method.getAnnotation(RedisLockAnn.class).menthodName())) {
key = method.getAnnotation(RedisLockAnn.class).menthodName();
}
try {
if (redisLock.lock("", key, expireTime)) {
re = joinPoint.proceed();
redisLock.unlock("", key);
}
} catch (Exception e) {
logger.error("redis锁:"+e.getMessage());
}finally {
redisLock.unlock("", key);
}
return re;
}
}

RedisUtil

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
* @Author: 李大本事
* @Date: 2020/6/5 17:09
*/
@Slf4j
@Component
public class RedisUtil {

private StringRedisTemplate redisTemplate;

@Autowired
public RedisUtil(StringRedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}

// 通用操作

/**
* 为给定[key]设置生存时间, 当[key]过期时(生存时间为0), 它会被自动删除
*
* @param key      键
* @param timeout  失效时间
* @param timeUnit 时间粒度
* @return 设置成功为true
*/
public Boolean setExpire(String key, long timeout, TimeUnit timeUnit) {
try {
redisTemplate.expire(key, timeout, timeUnit);
return Boolean.TRUE;
} catch (Exception e) {
log.error("class {RedisUtil} method {setExpire} with parameter {key={},timeout={},timeUnit={}} has error {}", key, timeout, timeUnit, e);
}
return null;
}

/**
* 删除[key]的值
*
* @param key 键
* @return 删除成功为true, 失败为false
*/
public Boolean remove(String key) {
try {
return redisTemplate.delete(key);
} catch (Exception e) {
log.error("class {RedisUtil} method {remove} with parameter {key={}} has error {}", key, e);
}
return null;
}

// String相关操作

/**
* 将字符串[value]关联到[key]
*
* @param key   键
* @param value 值
* @return 赋值成功为true
*/
public Boolean set(String key, String value) {
try {
redisTemplate.opsForValue().set(key, value);
return Boolean.TRUE;
} catch (Exception e) {
log.error("class {RedisUtil} method {set} with parameter {key={},value={}} has error {}", key, value, e);
}
return null;
}

/**
* 将字符串[value]关联到[key], 并设置TTL
*
* @param key      键
* @param value    值
* @param timeout  失效时间
* @param timeUnit 时间粒度
* @return 赋值成功为true
*/
public Boolean set(String key, String value, long timeout, TimeUnit timeUnit) {
try {
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
return Boolean.TRUE;
} catch (Exception e) {
log.error("class {RedisUtil} method {set} with parameter {key={},value={},timeout={},timeUnit={}} has error {}", key, value, timeout, timeUnit, e);
}
return null;
}

/**
* 在键[key]不存在的情况下, 将键[key]的值设置为[value]
*
* @param key   键
* @param value 值
* @return 赋值成功为true, 失败为false
*/
public Boolean setIfNotExist(String key, String value) {
try {
return redisTemplate.opsForValue().setIfAbsent(key, value);
} catch (Exception e) {
log.error("class {RedisUtil} method {setIfNotExist} with parameter {key={},value={}} has error {}", key, value, e);
}
return null;
}

/**
* 在键[key]不存在的情况下, 将键[key]的值设置为[value], 并设置TTL
*
* @param key      键
* @param value    值
* @param timeout  失效时间
* @param timeUnit 时间粒度
* @return 赋值成功为true, 失败为false
*/
public Boolean setIfNotExist(String key, String value, long timeout, TimeUnit timeUnit) {
try {
return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, timeUnit);
} catch (Exception e) {
log.error("class {RedisUtil} method {setIfNotExist} with parameter {key={},value={},timeout={},timeUnit={}} has error {}", key, value, timeout, timeUnit, e);
}
return null;
}

/**
* 键值自增
*
* @param key 键的名称
* @return 自增后的值
*/
public Long increment(String key) {
Long length = -1L;
try {
length = redisTemplate.opsForValue().increment(key);
redisTemplate.expire(key, 3, TimeUnit.DAYS);
} catch (Exception e) {
log.error("class {RedisUtil} method {increment} has error ", e);
}
return length;
}

/**
* 返回与键[key]相关联的字符串值
*
* @param key 键
* @return 返回key的值
*/
public String get(String key) {
try {
return redisTemplate.opsForValue().get(key);
} catch (Exception e) {
log.error("class {RedisUtil} method {set} with parameter {key={}} has error {}", key, e);
}
return null;
}

// Hash相关操作

/**
* 将哈希表[key]中域[field]的值设置为[value]
*
* @param key   键
* @param field 域
* @param value 值
* @return 赋值成功为true
*/
public Boolean setHash(String key, Object field, Object value) {
try {
redisTemplate.setHashValueSerializer(RedisSerializer.json());
redisTemplate.opsForHash().put(key, field, value);
return Boolean.TRUE;
} catch (Exception e) {
log.error("class {RedisUtil} method {setHash} with parameter {key={},field={},value={}} has error {}", key, field, value, e);
}
return null;
}

/**
* 将哈希表[key]中域[field]的值设置为[value], 并设置TTL
*
* @param key      键
* @param field    域
* @param value    值
* @param timeout  失效时间
* @param timeUnit 时间粒度
* @return 赋值成功为true
*/
public Boolean setHash(String key, Object field, Object value, long timeout, TimeUnit timeUnit) {
try {
redisTemplate.opsForHash().put(key, field, value);
setExpire(key, timeout, timeUnit);
return Boolean.TRUE;
} catch (Exception e) {
log.error("class {RedisUtil} method {setHash} with parameter {key={},field={},value={},timeout={},timeUnit={}} has error {}", key, field, value, timeout, timeUnit, e);
}
return null;
}

/**
* 当且仅当域[field]尚未存在于哈希表[key]的情况下, 将它的值设置为[value]
*
* @param key   键
* @param field 值
* @param value 域
* @return 赋值成功为true, 失败为false
*/
public Boolean setHashIfNotExist(String key, Object field, Object value) {
try {
return redisTemplate.opsForHash().putIfAbsent(key, field, value);
} catch (Exception e) {
log.error("class {RedisUtil} method {setHashIfNotExist} with parameter {key={},field={},value={}} has error {}", key, field, value, e);
}
return null;
}

/**
* 当且仅当域[field]尚未存在于哈希表[key]的情况下, 将它的值设置为[value], 并设置TTL
*
* @param key      键
* @param field    值
* @param value    域
* @param timeout  失效时间
* @param timeUnit 时间粒度
* @return 赋值成功为true, 失败为false
*/
public Boolean setHashIfNotExist(String key, Object field, Object value, long timeout, TimeUnit timeUnit) {
try {
setExpire(key, timeout, timeUnit);
return redisTemplate.opsForHash().putIfAbsent(key, field, value) && Boolean.TRUE;
} catch (Exception e) {
log.error("class {RedisUtil} method {setHashIfNotExist} with parameter {key={},field={},value={},timeout={},timeUnit={}} has error {}", key, field, value, timeout, timeUnit, e);
}
return null;
}

/**
* 同时将[map]中多个field-value(域-值)对设置到哈希表[key]中
*
* @param key 键
* @param map 域值对
* @return 赋值成功为true
*/
public Boolean setHashMap(String key, Map<Object, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return Boolean.TRUE;
} catch (Exception e) {
log.error("class {RedisUtil} method {setHashMap} with parameter {key={},map={}} has error {}", key, map, e);
}
return null;
}

/**
* 同时将[map]中多个field-value(域-值)对设置到哈希表[key]中, 并设置TTL, 时间粒度为 秒
*
* @param key 键
* @param map 域值对
* @return 赋值成功为true
*/
public Boolean setHashMap(String key, Map<Object, Object> map, long timeout) {
return setHashMap(key, map, timeout, TimeUnit.SECONDS);
}

/**
* 同时将[map]中多个field-value(域-值)对设置到哈希表[key]中, 并设置TTL
*
* @param key 键
* @param map 域值对
* @return 赋值成功为true
*/
public Boolean setHashMap(String key, Map<Object, Object> map, long timeout, TimeUnit timeUnit) {
try {
redisTemplate.setHashValueSerializer(RedisSerializer.json());
redisTemplate.opsForHash().putAll(key, map);
setExpire(key, timeout, timeUnit);
return Boolean.TRUE;
} catch (Exception e) {
log.error("class {RedisUtil} method {setHashMap} with parameter {key={},map={},timeout={},timeUnit={}} has error {}", key, map, timeout, timeUnit, e);
}
return null;
}

/**
* 返回哈希表[key]中给定域[field]的值
*
* @param key   键
* @param field 域
* @return 指定域的值
*/
public Object getHash(String key, Object field) {
try {
redisTemplate.setHashValueSerializer(RedisSerializer.json());
return redisTemplate.opsForHash().get(key, field);
} catch (Exception e) {
log.error("class {RedisUtil} method {getHash} with parameter {key={},field={}} has error {}", key, field, e);
}
return null;
}

/**
* 返回哈希表[key]中, 一个或多个给定域的值
*
* @param key 键
* @return 域值对
*/
public Map<Object, Object> getHashMap(String key) {
try {
redisTemplate.setHashValueSerializer(RedisSerializer.json());
return redisTemplate.opsForHash().entries(key);
} catch (Exception e) {
log.error("class {RedisUtil} method {getHash} with parameter {key={}} has error {}", key, e);
}
return null;
}

/**
* 批量获取keyList中的所有key的值
*
* @param keyList key值集合
* @return key值集合中所有值的集合
*/
public List<Object> getHashAll(List<String> keyList) {
try {
return redisTemplate.executePipelined((RedisCallback<LinkedHashMap<Object, Object>>) connection -> {
connection.openPipeline();
for (String key : keyList) {
byte[] keyByte = key.getBytes();
connection.hGetAll(keyByte);
}
return null;
});
} catch (Exception e) {
log.error("class {RedisUtil} method {getAll} with parameter {keyList={}} has error {}", keyList, e);
}
return null;
}

// List相关操作

/**
* 将[value]插入到列表[key]的表头(最左边)
*
* @param key   列表的名称
* @param value 值
* @return 表的长度
*/
public Long leftPush(String key, String value) {
try {
redisTemplate.setHashValueSerializer(RedisSerializer.json());
return redisTemplate.opsForList().leftPush(key, value);
} catch (Exception e) {
e.printStackTrace();
log.error("class {RedisUtil} method {leftPush} with parameter {key={},value={}} has error {}", key, value, e);
}
return null;
}

public Long removeValueOfList(String key, String value) {
try {
return redisTemplate.opsForList().remove(key, 0, value);
} catch (Exception e) {
e.printStackTrace();
log.error("class {RedisUtil} method {leftPush} with parameter {key={},value={}} has error {}", key, value, e);
}
return null;
}

/**
* 将[value]插入到列表[key]的表尾(最右边)
*
* @param key   列表的名称
* @param value 值
* @return 表的长度
*/
public Long rightPush(String key, String value) {
try {
return redisTemplate.opsForList().rightPush(key, value);
} catch (Exception e) {
log.error("class {RedisUtil} method {rightPush} with parameter {key={},value={}} has error {}", key, value, e);
}
return null;
}

/**
* 移除并返回列表[key]的头元素
*
* @param key 列表的名称
* @return 列表的头元素
*/
public String leftPop(String key) {
try {
return redisTemplate.opsForList().leftPop(key);
} catch (Exception e) {
log.error("class {RedisUtil} method {leftPop} with parameter {key={}} has error {}", key, e);
}
return null;
}

/**
* 移除并返回列表key的尾元素
*
* @param key 列表的名称
* @return 列表的尾元素
*/
public String rightPop(String key) {
try {
return redisTemplate.opsForList().rightPop(key);
} catch (Exception e) {
log.error("class {RedisUtil} method {rightPop} with parameter {key={}} has error {}", key, e);
}
return null;
}

/**
* 获取列表key的长度
*
* @param key 列表的名称
* @return 列表的长度
*/
public Long getListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
log.error("class {RedisUtil} method {getListSize} with parameter {key={}} has error {}", key, e);
}
return null;
}

public List<String> getAllList(String key) {
try {
Long end = redisTemplate.opsForList().size(key);
return redisTemplate.opsForList().range(key, 0, end);
} catch (Exception e) {
log.error("class {RedisUtil} method {getListSize} with parameter {key={}} has error {}", key, e);
}
return null;
}

public Long removeHashKey(String Key, String field) {
try {
return redisTemplate.opsForHash().delete(Key, field);

} catch (Exception e) {

log.error("class {RedisUtil} method {removeHashKey} with parameter {key={}} has error {}", Key, field, e);
}
return null;
}

public List<String> getListByCount(String key, Long size) {
try {
if (size > 0) {
--size;
}
return redisTemplate.opsForList().range(key, 0, size);
} catch (Exception e) {
log.error("class {RedisUtil} method {getListSize} with parameter {key={}} has error {}", key, e);
}
return null;

}
}

测试效果如下图

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: