Springboot整合Redis实现分布式锁

    技术2022-07-12  82

    新建Springboot项目,在pom文件加入以下依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 配置application.yml spring: redis: host: 127.0.0.1 port: 6379 database: 0 password: timeout: 10000 jedis: pool: max-active: 50 min-idle: 20 具体代码实现RedisLock.java package com.xx.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import java.util.Arrays; /** * Redis实现分布式锁 - setnx */ @Component public class RedisLock { private static final Logger logger = LoggerFactory.getLogger(RedisLock.class); @Autowired private StringRedisTemplate redisTemplate; @Autowired private DefaultRedisScript<Long> redisScript; private static final Long RELEASE_SUCCESS = 1L; /** * 加锁 * @param key 锁标识 * @param value 当前时间 + 超时时间 标识 * @return 加锁状态 */ public boolean lock(String key, String value){ //如果键不存在则新增,存在则不改变已经有的值 if (redisTemplate.opsForValue().setIfAbsent(key, value)){ logger.info("[redis分布式锁]获取成功"); return true; } String currentValue = redisTemplate.opsForValue().get(key); //如果锁过期 if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()){ //获取上一个锁的时间 String oldValue = redisTemplate.opsForValue().getAndSet(key, value); if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)){ logger.info("[redis分布式锁]获取成功"); return true; } } logger.info("[redis分布式锁]获取失败"); return false; } /** * 解锁 * @param key 锁标识 * @param value 当前时间 + 超时时间 标识 */ public void unlock(String key, String value){ try { String currentValue = redisTemplate.opsForValue().get(key); if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)){ redisTemplate.opsForValue().getOperations().delete(key); logger.info("[redis分布式锁]解锁成功"); } } catch (Exception e) { logger.error("[redis分布式锁]解锁异常,{}", e); } } /** * 解锁 -- lua脚本实现来保证原子性 * 1.判断操作线程是否是加锁的线程 * 2.如果是加锁线程,执行解锁操作 * 如果在判断是加锁的线程之后,并且执行解锁之前,锁到期了,被其他线程获得锁了,这时候再进行解锁就会解掉其他线程的锁 * @param key 锁标识 * @param value 当前时间 + 超时时间 标识 * @return 解锁状态(true:解锁成功 false:解锁失败) */ public boolean unlockWithLua(String key, String value){ //先判断是否是自己设置的锁,再执行删除 Long result = redisTemplate.execute(redisScript, Arrays.asList(key,value)); //返回最终结果 return RELEASE_SUCCESS.equals(result); } /** * @return lua脚本 */ @Bean public DefaultRedisScript<Long> defaultRedisScript() { DefaultRedisScript<Long> defaultRedisScript = new DefaultRedisScript<>(); defaultRedisScript.setResultType(Long.class); defaultRedisScript.setScriptText("if redis.call('get', KEYS[1]) == KEYS[2] then return redis.call('del', KEYS[1]) else return 0 end"); return defaultRedisScript; } }
    Processed: 0.016, SQL: 9