博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
redis RedisTemplate实现分布式锁
阅读量:6068 次
发布时间:2019-06-20

本文共 4362 字,大约阅读时间需要 14 分钟。

hot3.png

话不多说,上代码:

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisCallback;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.ValueOperations;import org.springframework.stereotype.Component; import java.util.Objects;import java.util.concurrent.TimeUnit; /** * Description: 通用Redis帮助类 * User: zhouzhou * Date: 2018-09-05 * Time: 15:39 */@Componentpublic class CommonRedisHelper {     	public static final String LOCK_PREFIX = "redis_lock";    	public static final int LOCK_EXPIRE = 300; // ms     	@Autowired    	RedisTemplate redisTemplate;        	/**     	*  最终加强分布式锁     	*     	* @param key key值     	* @return 是否获取到     	*/    	public boolean lock(String key){        		String lock = LOCK_PREFIX + key;        		// 利用lambda表达式        		return (Boolean) redisTemplate.execute((RedisCallback) connection -> {             			long expireAt = System.currentTimeMillis() + LOCK_EXPIRE + 1;            			Boolean acquire = connection.setNX(lock.getBytes(), String.valueOf(expireAt).getBytes());              			if (acquire) {                				return true;            			} else {                 				byte[] value = connection.get(lock.getBytes());                 				if (Objects.nonNull(value) && value.length > 0) {					long expireTime = Long.parseLong(new String(value));					if (expireTime < System.currentTimeMillis()) {                        // 如果锁已经过期                        						byte[] oldValue = connection.getSet(lock.getBytes(), String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes());                        // 防止死锁                        						return Long.parseLong(new String(oldValue)) < System.currentTimeMillis();					}				}			}			return false;        		});    	}     	/**     	* 删除锁     	*     	* @param key     	*/    	public void delete(String key) {        		redisTemplate.delete(key);	} }

如何使用呢,导入工具类后:

明星出轨Service{	public  List get明星出轨(String id){		List list = getRedis(id);		if(list == null){			boolean flag = CommonRedisHelper.lock(id);			if(flag){				list = findListBydB(id);				redis.set(id).value(list);				CommonRedisHelper.delete(id);			}else{				Threed.sleep(5000);				return this.get明星出轨(id);			}		}		return list;	}}

加锁成功执行完逻辑后, 必须解锁, 否则只能靠锁机制来解锁了不建议这么做。在web开发时,我们使用redis更多是使用redisTemplate,所以了解redisTemplate实现分布式锁势在必行。


PS:现在添加另一个更保持原子性的redis分布式锁的工具类

public class RedisTool {    @Autowired    RedisTemplate redisTemplate;    private static final Long SUCCESS = 1L;    /**     * 获取锁     * @param lockKey     * @param value     * @param expireTime:单位-秒     * @return     */    public  boolean getLock(String lockKey, String value, int expireTime){        boolean ret = false;        try{            String script = "if redis.call('setNx',KEYS[1],ARGV[1]) then if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end end";            RedisScript
redisScript = new DefaultRedisScript<>(script, String.class); Object result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey),value,expireTime); if(SUCCESS.equals(result)){ return true; } }catch(Exception e){ } return ret; } /** * 释放锁 * @param lockKey * @param value * @return */ public boolean releaseLock(String lockKey, String value){ String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; RedisScript
redisScript = new DefaultRedisScript<>(script, String.class); Object result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey),value); if(SUCCESS.equals(result)) { return true; } return false; }}

在使用上有一些小不同,可以根据业务进行融合

明星出轨Service{	public  List get明星出轨(String id){		List list = getRedis(id);		if(list == null){			boolean flag = redisTool.getLock("lockKey_"+id,id,1000 * 60);			if(flag){				list = findListBydB(id);				redis.set(id).value(list);				redisTool.releaseLock("lockKey_"+id,id);			}else{				Threed.sleep(5000);				return this.get明星出轨(id);			}		}		return list;	}}

PS:我们有发现一种新的分布式锁,这个方法也可以实现分布式锁

boolean flag = redisTemplate.opsForValue().setIfAbsent(key,value);

转载于:https://my.oschina.net/edisonOnCall/blog/3033104

你可能感兴趣的文章
mysql5.7 创建一个超级管理员
查看>>
【框架整合】Maven-SpringMVC3.X+Spring3.X+MyBatis3-日志、JSON解析、表关联查询等均已配置好...
查看>>
要想成为高级Java程序员需要具备哪些知识呢?
查看>>
带着问题去学习--Nginx配置解析(一)
查看>>
onix-文件系统
查看>>
java.io.Serializable浅析
查看>>
我的友情链接
查看>>
多线程之线程池任务管理通用模板
查看>>
CSS3让长单词与URL地址自动换行——word-wrap属性
查看>>
CodeForces 580B Kefa and Company
查看>>
开发规范浅谈
查看>>
Spark Streaming揭秘 Day29 深入理解Spark2.x中的Structured Streaming
查看>>
鼠标增强软件StrokeIt使用方法
查看>>
本地连接linux虚拟机的方法
查看>>
某公司面试java试题之【二】,看看吧,说不定就是你将要做的题
查看>>
BABOK - 企业分析(Enterprise Analysis)概要
查看>>
Linux 配置vnc,开启linux远程桌面
查看>>
NLog文章系列——如何优化日志性能
查看>>
Hadoop安装测试简单记录
查看>>
CentOS6.4关闭触控板
查看>>