使用StringRedisTemplate实现redis分布式锁
背景:单个接口可能同时被多个用户调用,但是每个用户使用的数据都是不一样,因此需要使用分布式锁解决数据减少了没有即使减少的问题
使用的指令来自的edis的setnx命令,setnx(k,v1),setnx(k.v2),当设置值为v1后,v2的设置无效
上图中启动了两台一样的服务,大多数情况,同一时间只有一条日志打印,但是定时任务是每15秒执行一次,数据有效期15秒,所以会有同一秒不同毫秒的日志打印
当时间设置为
1 | timed.task= 0 30 , 35 , 40 17 * * * |
同一秒内无法保证只执行一次
但是到了毫秒级别,不一样,实际上是不一样用户,但是定时任务部署多台服务器,这样可能存在问题
上图看到没有了在一秒内重合的日志打印,这边是调整了锁的过期时间
1 2 | 该行代码保证了原子性 Boolean setIfAbsent = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "001" , 25 , TimeUnit.SECONDS); |
相关代码部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | <?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> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | 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); } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
2022-02-28 java.io.FileNotFoundException: class path resource [templates/] cannot be resolved to absolute file path because it does not reside in the file system
2022-02-28 idea整合简单的oauth2认证服务器和资源认证服务器
2022-02-28 idea整合mybatis实现简单分页(一)