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; } }
测试效果如下图
相关文章推荐
- 分布式环境下基于redis解决在线客服坐席动态分配的问题
- Redis和MongoDB的复制、持久化、集群和集群管理功能
- hbase、mongodb、redis、lucene、 solr研究
- redis开发小结
- redis在windows下安装和PHP中使用
- 基于 twemproxy 搭建 redis 集群
- 安装配置redis
- Redis在windows下安装
- Windows下搭建Redis服务器
- scrapy-redis的使用(基于scrapy的改装)
- Redis【入门】
- Redis的位图bitmap
- Redis3.2开启远程访问
- Redis过期策略及实现原理
- 【Redis深度历险】那些年Redis的数据结构
- MySQL数据库与redis数据库的区别和redis数据库命令
- redis的事件机制 .
- ubuntu 安装/卸载 redis
- python-redis
- 单线程你别阻塞,Redis时延问题分析及应对