使用StringRedisTemplate实现redis分布式锁
背景:单个接口可能同时被多个用户调用,但是每个用户使用的数据都是不一样,因此需要使用分布式锁解决数据减少了没有即使减少的问题
使用的指令来自的edis的setnx命令,setnx(k,v1),setnx(k.v2),当设置值为v1后,v2的设置无效

上图中启动了两台一样的服务,大多数情况,同一时间只有一条日志打印,但是定时任务是每15秒执行一次,数据有效期15秒,所以会有同一秒不同毫秒的日志打印
当时间设置为
timed.task=0 30,35,40 17 * * *

同一秒内无法保证只执行一次

但是到了毫秒级别,不一样,实际上是不一样用户,但是定时任务部署多台服务器,这样可能存在问题

上图看到没有了在一秒内重合的日志打印,这边是调整了锁的过期时间

该行代码保证了原子性 Boolean setIfAbsent = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "001", 25, TimeUnit.SECONDS);
相关代码部分
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.redis</groupId>
<artifactId>redis-service</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<!--tomcat容器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.1</version>
</dependency>
</dependencies>
</project>
package com.redis;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* @Description:
* @Author: Yourheart
* @Create: 2023/2/28 14:38
*/
@SpringBootApplication
@EnableAsync
public class RedisApplication {
public static void main(String[] args) {
SpringApplication.run(RedisApplication.class, args);
}
}
package com.redis.task;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* @Description:
* @Author: Yourheart
* @Create: 2023/2/28 14:51
*/
@Configuration //1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling // 2.开启定时任务
@Slf4j
public class RedisTimeTask {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Scheduled(cron = "${timed.task}")//每天上午9点,下午5点执行
/**
* 单位都是毫秒
*/
// @Scheduled(initialDelay = 5000,fixedRate=5000)
// @Scheduled(initialDelay = 5000,fixedRate=20000)
@Async
public void timerSendMessage(){
String lockKey="test_001";
// Boolean setIfAbsent = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "001");
// stringRedisTemplate.expire(lockKey,25, TimeUnit.SECONDS);
Boolean setIfAbsent = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "001", 25, TimeUnit.SECONDS);
if (setIfAbsent){
try {
log.info("测试redis的分布式锁成功....");
} finally {
stringRedisTemplate.delete(lockKey);
}
}
}
}
server.port=8081 # 当天17点25分0秒 #timed.task=0 05,10,15,20,25,30,35,40,45,50,55 * * * * #每隔15秒执行一次 timed.task=0/15 * * * * * #timed.task= 0 0/5 * * * * #redis配置 spring.redis.host=127.0.0.1 spring.redis.port=6380 spring.redis.database=1 spring.redis.jedis.pool.max-active=8 spring.redis.jedis.pool.min-idle=0 spring.redis.password= spring.redis.lettuce.pool.max-wait=1000 logging.level.com.redis=debug logging.level.web=debug spring.devtools.add-properties=false
浙公网安备 33010602011771号