基于redisTemplate分布式锁
基于redisTemplate实现分布式锁
·
基于redisTemplate实现分布式锁
有两种实现方式
1、获取锁,获取失败不做其他处理 (不推荐)
2、获取锁,如果失败在重试时间内,重复获取(在简单项目中可以使用 美云)
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>simpleRedisLock</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>simpleRedisLock</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
RedisLockUtil
package com.example.simpleredislock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
* 设置等待时间,在时间内 循环操作
*/
@Component
@Slf4j
public class RedisLockUtilWithWaittime {
@Autowired
private RedisTemplate redisTemplate;
public static final String LOCKED = "TRUE";
public static final long EXPIRE = 120L;
public static final long ONE_MILLI_NANOS = 1000000L;
public static final long DEFAULT_TIME_OUT = 2000L;
public static final Random RANDOM = new Random();
public RedisLockUtilWithWaittime() {
}
// 等待时间重复获取
public <T> T executeSynchOperate(MainOperator<T> operator, String lockCacheKey, long milliTimeout) throws Exception {
try {
if (operator != null && lockCacheKey != null && milliTimeout >= 0L) {
boolean locked = false;
long startNano = System.nanoTime();
boolean waitFlag = milliTimeout > 0L;
long nanoTimeOut = (waitFlag ? milliTimeout : 50L) * 1000000L;
T resultObj = null;
try {
while(System.nanoTime() - startNano < nanoTimeOut) {
if (redisTemplate.opsForValue().setIfAbsent(lockCacheKey, LOCKED, 120L, TimeUnit.SECONDS)) {
locked = true;
break;
}
if (!waitFlag) {
break;
}
Thread.sleep(30L, RANDOM.nextInt(500));
}
resultObj = operator.executeInvokeLogic(locked);
} catch (Exception ex) {
log.error("处理逻辑", ex);
throw ex;
} finally {
if (locked) {
releaseRedisLock(lockCacheKey);
}
}
return resultObj;
} else {
throw new Exception("参数不合法");
}
} catch (Exception e) {
throw e;
}
}
/** @deprecated */
// 不推荐使用
@Deprecated
public <T> T executeSynchOperate(MainOperator<T> operator, String lockCacheKey) throws Exception {
boolean locked = false;
T resultObj = null;
try {
if (redisTemplate.opsForValue().setIfAbsent(lockCacheKey, LOCKED, 120L, TimeUnit.MICROSECONDS)) {
locked = true;
}
resultObj = operator.executeInvokeLogic(locked);
} catch (Exception ex) {
throw ex;
} finally {
if (locked) {
releaseRedisLock(lockCacheKey);
}
}
return resultObj;
}
/**
* 释放锁
* @param cacheKey
*/
public boolean releaseRedisLock(final String cacheKey){
Boolean deleteLock = redisTemplate.delete(cacheKey);
if (Boolean.TRUE.equals(deleteLock)) {
return true;
}
return false;
}
// 函数式接口
public interface MainOperator<T> {
boolean HOLD_LOCK_TAG = false;
T executeInvokeLogic(boolean result) throws Exception;
}
}
使用
package com.example.simpleredislock;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SimpleRedisLockApplicationTests {
@Autowired
private RedisLockUtilWithWaittime redisLockUtilWithWaittime;
@Test
void contextLoads() throws Exception {
testWithWaittime();
}
/**
* 在时间范围内重复执行操作,直到成功
* @return
* @throws Exception
*/
public String testWithWaittime() throws Exception {
String localKey = "myTest_1";
return redisLockUtilWithWaittime.executeSynchOperate(result -> {
if (!result) {
throw new Exception("");
}
// 数据库逻辑
return "ww";
}, localKey , 5000);
}
}
在项目启动时,应该把redis中的分布式锁删除。
推荐使用redission 实现分布式锁。
更多推荐
已为社区贡献1条内容
所有评论(0)