精华内容
下载资源
问答
  • * redis分布式锁-加锁 * @param redisTemplate redis 加锁解锁要保证同一个 * @param key 分布式锁key * @param value 分布式锁value 一般为随机数 * @param timeout 分布式锁过期时间 秒 * @param number 重...

    RedisUtil提供加锁,解锁,key和value生成

    public class RedisLockUtil {
    
        /**
         * redis分布式锁-加锁
         * @param redisTemplate redis 加锁解锁要保证同一个
         * @param key 分布式锁key
         * @param value 分布式锁value 一般为随机数
         * @param timeout 分布式锁过期时间 秒
         * @param number 重试次数
         * @param interval 重试间隔 毫秒
         * @return
         */
        public static boolean lock(RedisTemplate redisTemplate, String key, String value, int timeout, int number, int interval) {
            //加锁
            for (int i = 0; i < number; i++) {
                //尝试获取锁,成功则返回不成功则重试
                if (redisTemplate.opsForValue().setIfAbsent(key, value, Duration.ofSeconds(timeout))) {
                    return true;
                }
                //暂停
                try {
                    TimeUnit.MILLISECONDS.sleep(interval);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //最终获取不到锁返回失败
            return false;
        }
    
        public static boolean lock(RedisTemplate redisTemplate, String key, String value) {
            return lock(redisTemplate, key, value, 30, 3, 1000);
        }
    
        /**
         * 解锁脚本,防止线程将其他线程的锁释放
         */
        private static String UN_LOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    
        /**
         * redis分布式锁-解锁
         * @param redisTemplate redis 加锁解锁要保证同一个
         * @param key 分布式锁key
         * @param value 分布式锁value 一般为随机数
         * @return
         */
        public static void unLock(RedisTemplate redisTemplate, String key, String value) {
            //解锁
            redisTemplate.execute(new DefaultRedisScript<>(UN_LOCK_SCRIPT, Long.class), Collections.singletonList(key), value);
        }
    
        /**
         * 获取调用者的类名和方法名
         * @return
         */
        public static String getMethodPath() {
            StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
            //获取当前类名
            String className = stackTraceElement.getClassName();
            //获取当前方法名
            String methodName = stackTraceElement.getMethodName();
            return className + "#" + methodName;
        }
    
        /**
         * 获取随机数
         * @return
         */
        public static String getRandom() {
            return Objects.toString(ThreadLocalRandom.current().nextInt(0, 100000));
        }
    }
    

    测试代码,先在spring中接入redis再来尝试 Spring Boot中使用Redis数据库

    		//分布式锁key
            String key = RedisLockUtil.getMethodPath()+"_"+"100";
            //分布式锁value 一般为随机数
            String value = RedisLockUtil.getRandom();
            if (!RedisLockUtil.lock(stringRedisTemplate, key, value)) {
                //加锁失败
                 logger.info(">>>>>分布式锁<<<<< 重入锁失败 key:{} value:{}", key, value);
            }
            try {
                logger.info(">>>>>分布式锁<<<<< 加锁成功 key:{} value:{}", key, value);
                TimeUnit.SECONDS.sleep(20);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //解锁
                RedisLockUtil.unLock(stringRedisTemplate, key, value);
                logger.info(">>>>>分布式锁<<<<< 解锁成功 key:{} value:{}", key, value);
            }
    

    测试结果:在这里插入图片描述

    展开全文
  • RedisTemplate lettuce 实现分布式锁

    千次阅读 2019-01-15 16:45:08
    springboot2.x 以上使用redis时,默认使用了lettuce封装,比起jedis线程安全 import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.connection.RedisStringCommands; import org.spring...

    springboot2.x 以上使用redis时,默认使用了lettuce封装,比起jedis线程安全

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.data.redis.connection.RedisStringCommands;
    import org.springframework.data.redis.connection.ReturnType;
    import org.springframework.data.redis.core.RedisCallback;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.core.types.Expiration;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.Resource;
    import java.nio.charset.Charset;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @Description: 分布式锁工具类
     * @Author:
     * @CreateDate: 
     */
    @Component
    @Slf4j
    public class RedisLock {
        @Resource
        private RedisTemplate redisTemplate;
    
        public static final String UNLOCK_LUA;
    
        /**
         * 释放锁脚本,原子操作
         */
        static {
            StringBuilder sb = new StringBuilder();
            sb.append("if redis.call(\"get\",KEYS[1]) == ARGV[1] ");
            sb.append("then ");
            sb.append("    return redis.call(\"del\",KEYS[1]) ");
            sb.append("else ");
            sb.append("    return 0 ");
            sb.append("end ");
            UNLOCK_LUA = sb.toString();
        }
    
    
        /**
         * 获取分布式锁,原子操作
         * @param lockKey
         * @param requestId 唯一ID, 可以使用UUID.randomUUID().toString();
         * @param expire
         * @param timeUnit
         * @return
         */
        public boolean tryLock(String lockKey, String requestId, long expire, TimeUnit timeUnit) {
            try{
                RedisCallback<Boolean> callback = (connection) -> {
                    return connection.set(lockKey.getBytes(Charset.forName("UTF-8")), requestId.getBytes(Charset.forName("UTF-8")), Expiration.seconds(timeUnit.toSeconds(expire)), RedisStringCommands.SetOption.SET_IF_ABSENT);
                };
                return (Boolean)redisTemplate.execute(callback);
            } catch (Exception e) {
                log.error("redis lock error.", e);
            }
            return false;
        }
    
        /**
         * 释放锁
         * @param lockKey
         * @param requestId 唯一ID
         * @return
         */
        public boolean releaseLock(String lockKey, String requestId) {
            RedisCallback<Boolean> callback = (connection) -> {
                return connection.eval(UNLOCK_LUA.getBytes(), ReturnType.BOOLEAN ,1, lockKey.getBytes(Charset.forName("UTF-8")), requestId.getBytes(Charset.forName("UTF-8")));
            };
            return (Boolean)redisTemplate.execute(callback);
        }
    
        /**
         * 获取Redis锁的value值
         * @param lockKey
         * @return
         */
        public String get(String lockKey) {
            try {
                RedisCallback<String> callback = (connection) -> {
                    return new String(connection.get(lockKey.getBytes()), Charset.forName("UTF-8"));
                };
                return (String)redisTemplate.execute(callback);
            } catch (Exception e) {
                log.error("get redis occurred an exception", e);
            }
            return null;
        }
    
    }

    application.properties (使用lettuce配置)

    spring.redis.timeout=50000
    spring.redis.host=192.168.0.1
    spring.redis.password=123456
    spring.redis.database=0
    spring.redis.lettuce.pool.max-idle=8
    spring.redis.lettuce.pool.min-idle=1
    spring.redis.lettuce.pool.max-wait=30000
    spring.redis.lettuce.pool.max-active=8
    

     

    展开全文
  • 在分布式的集群环境下,如何保证某个代码片段只能一个节点来执行,以下的Redis的分布式锁就是其中一个实现方式。

    一、引入依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>
    

    二、redis(lettuce) 配置

    spring:
      redis:
        # Redis默认情况下有16个分片,这里配置具体使用的分片。默认是索引为0的分片。redis集群只有db0
        database: 0
        # Redis服务器地址
        host: 192.168.249.154
        # Redis服务器连接端口
        port: 6379
        # Redis服务器连接密码(默认为空)
        password:
        # 连接超时时间(毫秒)
        timeout: 2000s
        # 配置文件中添加 lettuce.pool 相关配置,则会使用到lettuce连接池
        lettuce:
          pool:
            # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
            max-wait: 60s
            # 连接池中的最大空闲连接 默认 8
            max-idle: 8
            # 连接池中的最小空闲连接 默认 0
            min-idle: 5
            # 连接池最大连接数(使用负值表示没有限制) 默认 8
            max-active: 8
    

    三、Redis配置类

    @Configuration
    public class RedisConfig {
        @Bean
        public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            return redisTemplate;
        }
    }
    

    四、Redis分布式锁工具类

    @Component
    public class RedisLockUtil {
        @Autowired
        private RedisTemplate<String, Object> redisTemplate;
    
        private static final byte[] SCRIPT_RELEASE_LOCK = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end".getBytes();
    
        /**
         * 尝试获取分布式锁
         *
         * @param key       键
         * @param requestId 请求ID
         * @param expire    锁的有效时间(秒)
         */
        public synchronized Boolean tryLock(String key, String requestId, long expire) {
            return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> redisConnection.set(key.getBytes(), requestId.getBytes(), Expiration.from(expire, TimeUnit.SECONDS), RedisStringCommands.SetOption.SET_IF_ABSENT));
        }
    
        /**
         * 释放分布式锁
         *
         * @param key       键
         * @param requestId 请求ID
         */
        public synchronized Boolean releaseLock(String key, String requestId) {
            return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> redisConnection.eval(SCRIPT_RELEASE_LOCK, ReturnType.BOOLEAN, 1, key.getBytes(), requestId.getBytes()));
        }
    }
    

    五、使用示例

    //获取锁
    Boolean lock = redisLockUtil.tryLock(rKeyLock, requestId, 10);
    if (null != lock && lock) {
        try {
            //TODO 业务处理
            
        } finally {
            //释放锁
            Boolean release = redisLockUtil.releaseLock(rKeyLock, requestId);
        }
    } else {
        log.warn("redis锁获取失败|{}|{}", rKeyLock, lock);
    }
    
    展开全文
  • springboot2.x redis lettuce实现分布式锁

    千次阅读 2019-03-16 08:22:10
    我查了很多redis分布式锁都是通过jedisclient来实现的,因为springboot2.x默认连接客户端是lettuce,所以引用一个大佬用jedis写的锁修改下。直接贴代码1.接口类public interface DistributedLock { public static...
    我查了很多redis分布式锁都是通过jedisclient来实现的,因为springboot2.x默认连接客户端是lettuce,所以引用一个大佬用jedis写的锁修改下。


    直接贴代码

    1.接口类

    public interface DistributedLock {
    	
    	public static final long TIMEOUT_MILLIS = 30000;
    	
    	public static final int RETRY_TIMES = 10;
    	
    	public static final long SLEEP_MILLIS = 500;
    	
    	public boolean lock(String key);
    	
    	public boolean lock(String key, int retryTimes);
    	
    	public boolean lock(String key, int retryTimes, long sleepMillis);
    	
    	public boolean lock(String key, long expire);
    	
    	public boolean lock(String key, long expire, int retryTimes);
    	
    	public boolean lock(String key, long expire, int retryTimes, long sleepMillis);
    	
    	public boolean releaseLock(String key);
    }
    复制代码

    2.依然是接口

    public abstract class AbstractDistributedLock implements DistributedLock {
    
    	@Override
    	public boolean lock(String key) {
    		return lock(key , TIMEOUT_MILLIS, RETRY_TIMES, SLEEP_MILLIS);
    	}
    
    	@Override
    	public boolean lock(String key, int retryTimes) {
    		return lock(key, TIMEOUT_MILLIS, retryTimes, SLEEP_MILLIS);
    	}
    
    	@Override
    	public boolean lock(String key, int retryTimes, long sleepMillis) {
    		return lock(key, TIMEOUT_MILLIS, retryTimes, sleepMillis);
    	}
    
    	@Override
    	public boolean lock(String key, long expire) {
    		return lock(key, expire, RETRY_TIMES, SLEEP_MILLIS);
    	}
    
    	@Override
    	public boolean lock(String key, long expire, int retryTimes) {
    		return lock(key, expire, retryTimes, SLEEP_MILLIS);
    	}
    
    }复制代码

    3.实现类

    @Component
    public class RedisDistributedLock extends AbstractDistributedLock {
    	
    	@Autowired
    	@Resource(name="redisTemplateMaster")
    	private RedisTemplate<Object,Object> redisTemplate;
    	
    	private final Logger logger = LoggerFactory.getLogger(RedisDistributedLock.class);
    	
    	//private RedisTemplate<Object, Object> redisTemplate;
    	
    	private ThreadLocal<String> lockFlag = new ThreadLocal<String>();
    	
    	public static final String UNLOCK_LUA;
    
        static {
            StringBuilder sb = new StringBuilder();
            sb.append("if redis.call(\"get\",KEYS[1]) == ARGV[1] ");
            sb.append("then ");
            sb.append("    return redis.call(\"del\",KEYS[1]) ");
            sb.append("else ");
            sb.append("    return 0 ");
            sb.append("end ");
            UNLOCK_LUA = sb.toString();
        }
    
        
        public RedisDistributedLock() {
    		super();
    	}
    
    //	public RedisDistributedLock(RedisTemplate<Object, Object> redisTemplate) {
    //		super();
    //		this.redisTemplate = redisTemplate;
    //	}
    
    	@Override
    	public boolean lock(String key, long expire, int retryTimes, long sleepMillis) {
    		boolean result = setRedis(key, expire);
    		// 如果获取锁失败,按照传入的重试次数进行重试
    		while((!result) && retryTimes-- > 0){
    			try {
    				logger.debug("lock failed, retrying..." + retryTimes);
    				Thread.sleep(sleepMillis);
    			} catch (InterruptedException e) {
    				return false;
    			}
    			result = setRedis(key , expire);
    		}
    		return result;
    	}
    	
    	private boolean setRedis(final String key, final long expire ) {
    		try{
    			
                RedisCallback<Boolean> callback = (connection) -> {
                	String uuid = UUID.randomUUID().toString();
                	lockFlag.set(uuid);
                    return connection.set(key.getBytes(Charset.forName("UTF-8")), uuid.getBytes(Charset.forName("UTF-8")), Expiration.milliseconds(expire), RedisStringCommands.SetOption.SET_IF_ABSENT);
                };
                return (Boolean)redisTemplate.execute(callback);
            } catch (Exception e) {
            	logger.error("redis lock error.", e);
            }
    		return false;
    	}
    	
    	
    	@Override
    	public boolean releaseLock(String key) {
    		// 释放锁的时候,有可能因为持锁之后方法执行时间大于锁的有效期,此时有可能已经被另外一个线程持有锁,所以不能直接删除
    		try {
    			 RedisCallback<Boolean> callback = (connection) -> {
    			    String value = lockFlag.get();
    	            return connection.eval(UNLOCK_LUA.getBytes(), ReturnType.BOOLEAN ,1, key.getBytes(Charset.forName("UTF-8")), value.getBytes(Charset.forName("UTF-8")));
    	        };
    		     return (Boolean)redisTemplate.execute(callback);
    		} catch (Exception e) {
    			logger.error("release lock occured an exception", e);
    		} finally {
    			// 清除掉ThreadLocal中的数据,避免内存溢出
    			lockFlag.remove();
    		}
    		return false;
    	}
    	
    }
    复制代码


    转载于:https://juejin.im/post/5c8cb043e51d4528641bdefb

    展开全文
  • 不适用分布式锁会怎样? 以抢购商品的高并发场景为例,通常单体的应用可以通过同步代码来实现顺序对数据库的操作,保证程序是按照预想来执行扣减操作的,不发生超卖情况。 但是在分布式系统中,同一个服务多实例...
  • spring boot 2.0后使用 lettuce实现的redis分布式锁 spring boot 2.0后使用 lettuce实现的redis分布式锁 http://yy870.com/article/36536.html http://zoole.wang/article/36536.html spring boot 2.0后使用 ...
  • 网上大部分是基于jedis的分布式锁 jedis是多线程下不是线程安全的 lettuce是基于netty线程安全性能高, springboot2.0都采用lettuce,所以分布式锁最好基于lettuce 2.分布式锁原理 采用原子操作如下: 如果不存在key...
  • 分布式锁 概念 任何一个系统都无法同时满足一致性(Consistency),可用性(Availability),分区容错性(Partition tolerance), 只能同事满足2个; 分布式锁就是为了解决数据一致性问题. 应用场景 涉及到多个实例进程...
  • Spring aop优雅实现redis分布式锁 aop应用redis分布式锁

    千次阅读 热门讨论 2019-08-02 21:39:03
    redis分布式锁切面实现说明RedisLockUtilsRedisLockAspect@DistributedLock 说明 可以满足绝大部分分布式锁需求,请直接看代码,方法名很明了,注释也很明了啦,希望您看到不足的地方或者有不同见解的,还请再评论里...
  • springboot新版本使用lettuce取代了jedis连接redis,分布式锁实现代码如下 import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data....
  • Redis分布式锁

    万次阅读 2020-03-24 01:02:25
    特定的场景下,往往依靠分布式锁,常见的分布式锁实现方式有Redis分布式锁以及Zookeeper分布式锁。Redis分布式锁在项目编码中更为常见,比较成熟的框架有Redisson,就实现了分布式锁。虽然项目中我们可以使用比较...
  • springboot升级到2.0之后,关联的spring-...鉴于spring-data默认只提供了setnx不带过期时间的入口,为了防止分布式锁的死锁只能自己来实现setnx关键词 以下是使用默认的stringRedisTemplate实现setnx的过程: /**...
  • 在上一小节我们详细讲解了使用MYSQL数据库实现分布式锁的技术方案及实现细节案例,本节我们使用zookeeper方式实现分布式锁,原理同上,依然是使用共享资源获取锁,从而实现分布式锁。zookeeper具备高可用、可重入、...
  • 分布式锁的演进 基本原理 我们可以同时去一个地方“占坑”,如果占到,就执行逻辑。否则就必须等待,直到释放锁。“占坑”可以去redis,可以去数据库,可以去任何大家都能访问的地方。等待可以自旋的方式。 阶段...
  • Redis 分布式锁

    2020-11-12 15:50:37
    文章目录分布式锁Redis分布式锁setnxotherRedissonredisson分布式锁原理RedissonReadWriteLockRedissonMultiLockRedissonRedLock性能继续提高? 分布式锁 synchronized 和 lock 都是 jvm 级别的锁, 只能锁单机的并发...
  • docker exec -it redis redis-cli 发送给全部会话 public Map<... //1、占分布式锁,。去redis占坑 Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock",...
  • Redis-4 分布式锁

    2021-01-12 15:51:41
    Redis分布式锁实现-java 分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁。本篇博客将介绍第二种方式,基于Redis实现分布式锁。本章给予的java工具类分布式锁...
  • 分布式锁

    2021-04-22 11:01:41
    分布式锁 分布式锁介绍 什么是分布式 一个大型的系统往往被分为几个子系统来做,一个子系统可以部署在多个服务器上, 分布式就是通过计算机网络将后端工作分布到多台主机上,多个主机一起协同完成工作 什么是锁 java...
  • SpringBoot Redis分布式锁

    2021-01-13 17:22:17
    SpringBoot系列-redis分布式锁实现SpringBoot整合Redis分布式锁教程前言一、技术介绍1.Redis是什么?2.分布式锁是什么?二、使用步骤1.引入maven库2.封装Redis分布式锁工具类3.配置文件4.单元测试总结 SpringBoot...
  • 而目前比较常见的方案是通过Redis来实现分布式锁,网上关于分布式锁的实现方式有很多,早期主要是基于Redisson等客户端,但在Spring Boot2.x以上版本中使用Redis时,其客户端库已经默认使用lettuce。 所以本文将直接...
  • 使用redis分布式锁,来确保多个服务对共享数据操作的唯一性一般来说有StringRedisTemplate和RedisTemplate两种redis操作模板。 根据key-value的类型决定使用哪种模板,如果k-v均是String类型,则使用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,940
精华内容 776
关键字:

lettuce分布式锁