SpringBoot集成RedisTemplate的實(shí)現(xiàn)示例
一、?? 基礎(chǔ)配置與工具類
1. Maven依賴 (pom.xml)
<dependencies>
<!-- Spring Boot Redis Starter 依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 其他依賴... -->
</dependencies>
2. 應(yīng)用配置 (application.yml)
spring:
redis:
host: localhost # Redis服務(wù)器地址
port: 6379 # Redis服務(wù)器端口
password: # Redis訪問(wèn)密碼,如果沒(méi)有密碼則不配置
database: 0 # Redis數(shù)據(jù)庫(kù)索引(0-15)
lettuce:
pool:
max-active: 8 # 連接池最大連接數(shù)
max-idle: 8 # 連接池最大空閑連接數(shù)
min-idle: 0 # 連接池最小空閑連接數(shù)
max-wait: 200ms # 獲取連接的最大等待時(shí)間
shutdown-timeout: 100ms # 關(guān)閉超時(shí)時(shí)間
timeout: 2000ms # 連接超時(shí)時(shí)間
3. Redis配置類 (RedisConfig.java)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
/**
* Redis配置類
* 配置RedisTemplate的序列化方式,解決鍵值對(duì)存儲(chǔ)的亂碼問(wèn)題
*
* @author Developer
* @version 1.0
* @since 2025-09-22
*/
@Configuration
public class RedisConfig {
/**
* 配置RedisTemplate Bean
* 設(shè)置key和value的序列化方式,避免存儲(chǔ)亂碼
*
* @param connectionFactory Redis連接工廠,由Spring自動(dòng)注入
* @return 配置好的RedisTemplate實(shí)例
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 設(shè)置連接工廠
template.setConnectionFactory(connectionFactory);
// 使用StringRedisSerializer來(lái)序列化和反序列化redis的key值
StringRedisSerializer stringSerializer = new StringRedisSerializer();
template.setKeySerializer(stringSerializer);
template.setHashKeySerializer(stringSerializer);
// 使用Jackson2JsonRedisSerializer來(lái)序列化和反序列化redis的value值
GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();
template.setValueSerializer(jsonSerializer);
template.setHashValueSerializer(jsonSerializer);
template.afterPropertiesSet();
return template;
}
}
4. Redis通用工具類 (RedisUtil.java)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* Redis工具類
* 封裝常用Redis操作,提供便捷的API調(diào)用方式
*
* @author Developer
* @version 1.0
* @since 2025-09-22
*/
@Component
public class RedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// ============================== 通用方法 ==============================
/**
* 刪除鍵
*
* @param key 要?jiǎng)h除的鍵
* @return true表示刪除成功,false表示失敗
*/
public Boolean delete(String key) {
return redisTemplate.delete(key);
}
/**
* 判斷鍵是否存在
*
* @param key 要檢查的鍵
* @return true表示存在,false表示不存在
*/
public Boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
/**
* 設(shè)置鍵的過(guò)期時(shí)間
*
* @param key 鍵
* @param timeout 過(guò)期時(shí)間
* @param unit 時(shí)間單位
* @return true表示設(shè)置成功,false表示失敗
*/
public Boolean expire(String key, long timeout, TimeUnit unit) {
return redisTemplate.expire(key, timeout, unit);
}
/**
* 獲取鍵的剩余生存時(shí)間(秒)
*
* @param key 鍵
* @return 剩余生存時(shí)間(秒),-1表示永不過(guò)期,-2表示鍵不存在
*/
public Long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
// ============================== String操作 ==============================
/**
* 設(shè)置鍵值對(duì)
*
* @param key 鍵
* @param value 值
*/
public void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 設(shè)置鍵值對(duì)并指定過(guò)期時(shí)間
*
* @param key 鍵
* @param value 值
* @param timeout 過(guò)期時(shí)間
* @param unit 時(shí)間單位
*/
public void set(String key, Object value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
/**
* 只有在鍵不存在時(shí)設(shè)置鍵值對(duì)(分布式鎖基礎(chǔ)實(shí)現(xiàn))
*
* @param key 鍵
* @param value 值
* @param timeout 過(guò)期時(shí)間
* @param unit 時(shí)間單位
* @return true表示設(shè)置成功,false表示鍵已存在
*/
public Boolean setIfAbsent(String key, Object value, long timeout, TimeUnit unit) {
return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit);
}
/**
* 獲取鍵的值
*
* @param key 鍵
* @return 對(duì)應(yīng)的值,鍵不存在時(shí)返回null
*/
public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
/**
* 將鍵中存儲(chǔ)的數(shù)字值增一(原子操作)
*
* @param key 鍵
* @param delta 增量,可以為負(fù)值
* @return 增減后的值
*/
public Long increment(String key, long delta) {
return redisTemplate.opsForValue().increment(key, delta);
}
// ============================== Hash操作 ==============================
/**
* 向Hash中添加單個(gè)字段
*
* @param key Hash鍵
* @param hashKey Hash字段鍵
* @param value 字段值
*/
public void hPut(String key, String hashKey, Object value) {
redisTemplate.opsForHash().put(key, hashKey, value);
}
/**
* 向Hash中添加多個(gè)字段
*
* @param key Hash鍵
* @param map 字段映射表
*/
public void hPutAll(String key, Map<String, Object> map) {
redisTemplate.opsForHash().putAll(key, map);
}
/**
* 獲取Hash中指定字段的值
*
* @param key Hash鍵
* @param hashKey Hash字段鍵
* @return 字段值,字段不存在時(shí)返回null
*/
public Object hGet(String key, String hashKey) {
return redisTemplate.opsForHash().get(key, hashKey);
}
/**
* 獲取Hash中所有字段和值
*
* @param key Hash鍵
* @return 包含所有字段和值的Map
*/
public Map<Object, Object> hGetAll(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* 刪除Hash中的一個(gè)或多個(gè)字段
*
* @param key Hash鍵
* @param hashKeys 要?jiǎng)h除的字段鍵
* @return 刪除的字段數(shù)量
*/
public Long hDelete(String key, Object... hashKeys) {
return redisTemplate.opsForHash().delete(key, hashKeys);
}
// ============================== List操作 ==============================
/**
* 向列表左側(cè)添加元素
*
* @param key 列表鍵
* @param value 要添加的元素
* @return 添加后列表的長(zhǎng)度
*/
public Long lPush(String key, Object value) {
return redisTemplate.opsForList().leftPush(key, value);
}
/**
* 獲取列表指定范圍內(nèi)的元素
*
* @param key 列表鍵
* @param start 起始索引(0表示第一個(gè)元素)
* @param end 結(jié)束索引(-1表示最后一個(gè)元素)
* @return 元素列表
*/
public List<Object> lRange(String key, long start, long end) {
return redisTemplate.opsForList().range(key, start, end);
}
/**
* 從列表左側(cè)彈出元素
*
* @param key 列表鍵
* @return 彈出的元素,列表為空時(shí)返回null
*/
public Object lPop(String key) {
return redisTemplate.opsForList().leftPop(key);
}
// ============================== Set操作 ==============================
/**
* 向集合中添加一個(gè)或多個(gè)元素
*
* @param key 集合鍵
* @param values 要添加的元素
* @return 成功添加的元素?cái)?shù)量(忽略已存在的元素)
*/
public Long sAdd(String key, Object... values) {
return redisTemplate.opsForSet().add(key, values);
}
/**
* 獲取集合中的所有元素
*
* @param key 集合鍵
* @return 包含所有元素的Set
*/
public Set<Object> sMembers(String key) {
return redisTemplate.opsForSet().members(key);
}
/**
* 判斷元素是否在集合中
*
* @param key 集合鍵
* @param value 要檢查的元素
* @return true表示元素存在,false表示不存在
*/
public Boolean sIsMember(String key, Object value) {
return redisTemplate.opsForSet().isMember(key, value);
}
// ============================== ZSet操作 ==============================
/**
* 向有序集合中添加元素
*
* @param key 有序集合鍵
* @param value 元素值
* @param score 元素分?jǐn)?shù)(用于排序)
* @return true表示添加成功,false表示元素已存在(更新分?jǐn)?shù))
*/
public Boolean zAdd(String key, Object value, double score) {
return redisTemplate.opsForZSet().add(key, value, score);
}
/**
* 獲取有序集合指定排名范圍內(nèi)的元素(按分?jǐn)?shù)升序)
*
* @param key 有序集合鍵
* @param start 起始排名(0表示第一名)
* @param end 結(jié)束排名(-1表示最后一名)
* @return 元素集合
*/
public Set<Object> zRange(String key, long start, long end) {
return redisTemplate.opsForZSet().range(key, start, end);
}
/**
* 獲取有序集合指定排名范圍內(nèi)的元素及其分?jǐn)?shù)(按分?jǐn)?shù)降序)
*
* @param key 有序集合鍵
* @param start 起始排名(0表示第一名)
* @param end 結(jié)束排名(-1表示最后一名)
* @return 包含元素和分?jǐn)?shù)的TypedTuple集合
*/
public Set<ZSetOperations.TypedTuple<Object>> zRangeWithScores(String key, long start, long end) {
return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
}
/**
* 增加有序集合中元素的分?jǐn)?shù)
*
* @param key 有序集合鍵
* @param value 元素值
* @param delta 增量
* @return 增加后的分?jǐn)?shù)
*/
public Double zIncrementScore(String key, Object value, double delta) {
return redisTemplate.opsForZSet().incrementScore(key, value, delta);
}
}
二、?? 實(shí)戰(zhàn)應(yīng)用
1. 分布式鎖服務(wù) (DistributedLockService.java)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
/**
* 分布式鎖服務(wù)
* 基于Redis實(shí)現(xiàn)分布式鎖,保證分布式環(huán)境下資源訪問(wèn)的互斥性
* 使用Lua腳本保證鎖釋放操作的原子性
*
* @author Developer
* @version 1.0
*/
@Service
public class DistributedLockService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// Lua腳本:只有鎖的值與傳入的請(qǐng)求標(biāo)識(shí)匹配時(shí)才刪除鎖(保證原子性)
private static final String RELEASE_LOCK_SCRIPT =
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) " +
"else " +
"return 0 " +
"end";
private static final String LOCK_PREFIX = "lock:";
/**
* 嘗試獲取分布式鎖
*
* @param lockKey 鎖的業(yè)務(wù)鍵(會(huì)自動(dòng)添加前綴)
* @param requestId 請(qǐng)求標(biāo)識(shí)(需保證全局唯一)
* @param expireTime 鎖的過(guò)期時(shí)間(防止死鎖)
* @param unit 時(shí)間單位
* @return true表示獲取鎖成功,false表示失敗
*/
public Boolean tryLock(String lockKey, String requestId, long expireTime, TimeUnit unit) {
String fullLockKey = LOCK_PREFIX + lockKey;
return redisTemplate.opsForValue().setIfAbsent(fullLockKey, requestId, expireTime, unit);
}
/**
* 釋放分布式鎖
* 使用Lua腳本保證檢查鎖歸屬和釋放鎖的原子性操作
*
* @param lockKey 鎖的業(yè)務(wù)鍵
* @param requestId 請(qǐng)求標(biāo)識(shí)(必須與獲取鎖時(shí)使用的標(biāo)識(shí)一致)
* @return true表示釋放成功,false表示釋放失?。ㄦi不存在或不屬于當(dāng)前請(qǐng)求)
*/
public Boolean releaseLock(String lockKey, String requestId) {
String fullLockKey = LOCK_PREFIX + lockKey;
// 創(chuàng)建Redis腳本對(duì)象
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(RELEASE_LOCK_SCRIPT, Long.class);
// 執(zhí)行Lua腳本(原子操作)
Long result = redisTemplate.execute(redisScript, Collections.singletonList(fullLockKey), requestId);
return result != null && result == 1;
}
}
2.緩存實(shí)戰(zhàn):緩存穿透/擊穿/雪崩解決方案(CacheService.java)
@Service
public class CacheService {
@Autowired
private RedisUtil redisUtil;
private static final String CACHE_PREFIX = "cache:";
private static final String NULL_CACHE = "NULL"; // 緩存空值的標(biāo)識(shí)
/**
* 防緩存穿透:查詢商品信息
*/
public Product getProductById(Long productId) {
String key = CACHE_PREFIX + "product:" + productId;
// 1. 先從緩存中查詢
Product product = (Product) redisUtil.get(key);
if (product != null) {
// 如果緩存的是空值,直接返回null,防止緩存穿透
if (NULL_CACHE.equals(product)) {
return null;
}
return product;
}
// 2. 加鎖,防止緩存擊穿
synchronized (this) {
// 再次檢查緩存,因?yàn)榭赡芤呀?jīng)被其他線程填充
product = (Product) redisUtil.get(key);
if (product != null) {
if (NULL_CACHE.equals(product)) {
return null;
}
return product;
}
// 3. 緩存中沒(méi)有,則查詢數(shù)據(jù)庫(kù)
product = productRepository.findById(productId).orElse(null);
if (product == null) {
// 數(shù)據(jù)庫(kù)不存在,緩存一個(gè)空值(短時(shí)間),防止緩存穿透
redisUtil.set(key, NULL_CACHE, 60, TimeUnit.SECONDS);
} else {
// 數(shù)據(jù)庫(kù)存在,寫(xiě)入緩存,并設(shè)置隨機(jī)過(guò)期時(shí)間防止雪崩
long expireTime = 1800 + new Random().nextInt(600); // 基礎(chǔ)30分鐘 + 隨機(jī)10分鐘
redisUtil.set(key, product, expireTime, TimeUnit.SECONDS);
}
return product;
}
}
}
3. 排行榜服務(wù) (RankingService.java)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import java.util.Set;
/**
* 排行榜服務(wù)
* 使用Redis有序集合(ZSet)實(shí)現(xiàn)排行榜功能
* 支持更新分?jǐn)?shù)、獲取排名、獲取榜單等功能
*
* @author Developer
* @version 1.0
*/
@Service
public class RankingService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String RANKING_KEY = "leaderboard";
/**
* 更新玩家分?jǐn)?shù)
* 如果玩家不存在則添加,存在則更新分?jǐn)?shù)
*
* @param playerId 玩家ID
* @param score 玩家分?jǐn)?shù)
*/
public void updatePlayerScore(String playerId, double score) {
redisTemplate.opsForZSet().add(RANKING_KEY, playerId, score);
}
/**
* 獲取前N名玩家(按分?jǐn)?shù)降序)
*
* @param topN 前N名
* @return 包含玩家和分?jǐn)?shù)的集合
*/
public Set<ZSetOperations.TypedTuple<Object>> getTopPlayers(int topN) {
return redisTemplate.opsForZSet().reverseRangeWithScores(RANKING_KEY, 0, topN - 1);
}
/**
* 獲取玩家排名(按分?jǐn)?shù)降序,從1開(kāi)始)
*
* @param playerId 玩家ID
* @return 玩家排名,第1名返回1,未上榜返回null
*/
public Long getPlayerRank(String playerId) {
// 獲取降序排名(0-based)
Long rank = redisTemplate.opsForZSet().reverseRank(RANKING_KEY, playerId);
return rank != null ? rank + 1 : null;
}
/**
* 增加玩家分?jǐn)?shù)(原子操作)
*
* @param playerId 玩家ID
* @param delta 增量
* @return 增加后的分?jǐn)?shù)
*/
public Double incrementPlayerScore(String playerId, double delta) {
return redisTemplate.opsForZSet().incrementScore(RANKING_KEY, playerId, delta);
}
}
三、?? 測(cè)試控制器
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.web.bind.annotation.*;
import java.util.Set;
import java.util.UUID;
/**
* Redis操作測(cè)試控制器
* 提供HTTP接口測(cè)試各種Redis功能
*
* @author Developer
* @version 1.0
*/
@RestController
@RequestMapping("/api/redis")
public class TestController {
@Autowired
private StringOpsService stringOpsService;
@Autowired
private HashOpsService hashOpsService;
@Autowired
private DistributedLockService distributedLockService;
@Autowired
private RankingService rankingService;
/**
* 測(cè)試String操作
*
* @return 操作結(jié)果消息
*/
@GetMapping("/test-string")
public String testStringOps() {
stringOpsService.setWithExpire("test:key", "Hello Redis!", 10, TimeUnit.MINUTES);
return "String operation test completed.";
}
/**
* 測(cè)試分布式鎖功能
*
* @return 鎖操作結(jié)果消息
*/
@GetMapping("/test-lock")
public String testDistributedLock() {
String lockKey = "resource:1";
String requestId = UUID.randomUUID().toString();
boolean locked = distributedLockService.tryLock(lockKey, requestId, 10, TimeUnit.SECONDS);
if (locked) {
try {
// 模擬業(yè)務(wù)操作
Thread.sleep(2000);
return "Lock acquired and operation performed.";
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return "Operation interrupted.";
} finally {
distributedLockService.releaseLock(lockKey, requestId);
}
} else {
return "Failed to acquire lock.";
}
}
/**
* 更新玩家分?jǐn)?shù)
*
* @param playerId 玩家ID
* @param score 分?jǐn)?shù)
* @return 操作結(jié)果消息
*/
@PostMapping("/update-score/{playerId}")
public String updateScore(@PathVariable String playerId, @RequestParam double score) {
rankingService.updatePlayerScore(playerId, score);
return "Score updated for player: " + playerId;
}
/**
* 獲取排行榜前N名玩家
*
* @param n 前N名
* @return 玩家排名集合
*/
@GetMapping("/leaderboard/top/{n}")
public Set<ZSetOperations.TypedTuple<Object>> getTopPlayers(@PathVariable int n) {
return rankingService.getTopPlayers(n);
}
}
到此這篇關(guān)于SpringBoot集成RedisTemplate的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)SpringBoot RedisTemplate內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 在SpringBoot中注入RedisTemplate實(shí)例異常的解決方案
- SpringBoot整合Redis使用@Cacheable和RedisTemplate
- SpringBoot整合RedisTemplate實(shí)現(xiàn)緩存信息監(jiān)控的步驟
- 詳解SpringBoot使用RedisTemplate操作Redis的5種數(shù)據(jù)類型
- SpringBoot整合Redis使用RedisTemplate和StringRedisTemplate
- springboot使用redisRepository和redistemplate操作redis的過(guò)程解析
- SpringBoot混合使用StringRedisTemplate和RedisTemplate的坑及解決
相關(guān)文章
Java利用Spire.Doc for Java實(shí)現(xiàn)在Word文檔中插入圖片
本文將深入探討如何利用 Spire.Doc for Java 這一強(qiáng)大庫(kù),在 Java 程序中高效、靈活地實(shí)現(xiàn) Word 文檔的圖片插入功能,包括不同環(huán)繞方式和指定位置的插入,有需要的小伙伴可以了解下2025-10-10
SpringCloud網(wǎng)關(guān)組件Gateway原理深度解析
Spring Cloud Gateway是Spring Cloud微服務(wù)生態(tài)下的網(wǎng)關(guān)組件,一些基礎(chǔ)的請(qǐng)求預(yù)處理的邏輯可以統(tǒng)一實(shí)現(xiàn)在網(wǎng)關(guān)這一層,這樣業(yè)務(wù)服務(wù)只需要專注于處理業(yè)務(wù)邏輯即可,所以本文就帶大家深度解析網(wǎng)關(guān)組件Gateway,需要的朋友可以參考下2023-07-07
通過(guò)maven配置不同的開(kāi)發(fā)環(huán)境方式
文章介紹了如何使用Maven來(lái)控制不同環(huán)境(開(kāi)發(fā)、測(cè)試、生產(chǎn))下的配置文件的加載,具體方法包括在項(xiàng)目目錄下創(chuàng)建特定文件夾存放環(huán)境配置文件,以及在pom文件中添加相關(guān)配置,這樣,可以方便地通過(guò)選擇環(huán)境并刷新來(lái)啟動(dòng)項(xiàng)目,提高了配置管理的效率和便捷性2025-10-10
Java線程中斷及線程中斷的幾種使用場(chǎng)景小結(jié)
在并發(fā)編程中,合理使用線程中斷機(jī)制可以提高程序的魯棒性和可維護(hù)性,本文主要介紹了Java線程中斷及線程中斷的幾種使用場(chǎng)景小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01
Spring SmartLifecycle:如何精準(zhǔn)控制Bean的生命周期
這篇文章主要介紹了Spring SmartLifecycle:如何精準(zhǔn)控制Bean的生命周期問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03
Java aop面向切面編程(aspectJweaver)案例詳解
這篇文章主要介紹了Java aop面向切面編程(aspectJweaver)案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08

