SpringBoot整合Redis的實(shí)踐
前言
Redis(Remote Dictionary Server)是一個(gè)開(kāi)源的內(nèi)存數(shù)據(jù)庫(kù)(In-Memory Database),也被稱為數(shù)據(jù)結(jié)構(gòu)服務(wù)器,它支持存儲(chǔ)鍵值對(duì),并提供多種數(shù)據(jù)結(jié)構(gòu)的操作。
Redis具有高性能、豐富的數(shù)據(jù)結(jié)構(gòu)和靈活的持久化機(jī)制,因此在緩存、會(huì)話存儲(chǔ)、排行榜、計(jì)數(shù)器、消息隊(duì)列等場(chǎng)景中得到廣泛的應(yīng)用。
Redis主要有以下特點(diǎn):
內(nèi)存數(shù)據(jù)庫(kù):Redis的所有數(shù)據(jù)都存儲(chǔ)在內(nèi)存中,這使得它具有非常高的讀寫速度。雖然數(shù)據(jù)存儲(chǔ)在內(nèi)存中,但Redis也支持將數(shù)據(jù)持久化到磁盤上,以確保數(shù)據(jù)的安全性和可恢復(fù)性。鍵值存儲(chǔ):Redis以鍵值對(duì)(Key-Value)的形式存儲(chǔ)數(shù)據(jù),其中鍵是唯一的,而值可以是字符串、列表、哈希表、集合、有序集合等多種數(shù)據(jù)結(jié)構(gòu)。豐富的數(shù)據(jù)結(jié)構(gòu):Redis支持多種數(shù)據(jù)結(jié)構(gòu)的操作,如字符串(String)、列表(List)、哈希表(Hash)、集合(Set)、有序集合(Sorted Set)等。這些數(shù)據(jù)結(jié)構(gòu)可以方便地滿足不同應(yīng)用場(chǎng)景的需求。高性能:Redis是一個(gè)單線程的服務(wù)器,它采用異步I/O和事件驅(qū)動(dòng)的方式,使得它能夠在單個(gè)線程中處理大量的并發(fā)請(qǐng)求,從而獲得較高的性能。持久化:Redis提供了兩種方式的數(shù)據(jù)持久化:RDB快照和AOF日志。RDB快照可以將當(dāng)前內(nèi)存中的數(shù)據(jù)以二進(jìn)制形式寫入磁盤,而AOF日志則記錄了所有寫命令,用于在服務(wù)重啟后重放這些命令以還原數(shù)據(jù)。分布式:Redis支持通過(guò)主從復(fù)制(Master-Slave Replication)實(shí)現(xiàn)數(shù)據(jù)的讀寫分離和高可用性。此外,Redis還提供了集群(Cluster)模式,可以將數(shù)據(jù)分布在多個(gè)節(jié)點(diǎn)上,從而實(shí)現(xiàn)數(shù)據(jù)的橫向擴(kuò)展。支持多種編程語(yǔ)言:Redis提供了多種編程語(yǔ)言的客戶端庫(kù),可以方便地在各種不同的編程語(yǔ)言中使用Redis。
Spring Data Redis是Spring Framework生態(tài)系統(tǒng)中的一個(gè)模塊,用于簡(jiǎn)化使用Redis的開(kāi)發(fā)。它提供了對(duì)Redis的集成和操作的抽象層,使得在Spring應(yīng)用程序中使用Redis變得更加方便和高效。
通過(guò)使用Spring Data Redis,開(kāi)發(fā)人員可以更加便捷地操作Redis數(shù)據(jù)庫(kù),減少了與Redis交互的復(fù)雜性和重復(fù)性工作。同時(shí),它與Spring Framework的其他模塊和特性無(wú)縫集成,提供了更強(qiáng)大的功能和靈活性。
Spring Data Redis主要提供以下功能和特性:
對(duì)象映射:Spring Data Redis允許開(kāi)發(fā)人員使用注解或XML配置將Java對(duì)象與Redis數(shù)據(jù)存儲(chǔ)之間進(jìn)行映射。通過(guò)這種方式,可以將復(fù)雜的Java對(duì)象直接存儲(chǔ)到Redis中,并通過(guò)簡(jiǎn)單的API進(jìn)行讀取和更新。高級(jí)查詢:Spring Data Redis支持通過(guò)注解或方法命名約定進(jìn)行高級(jí)查詢,例如按條件查詢、排序、分頁(yè)等操作。這樣可以方便地使用查詢語(yǔ)言來(lái)檢索和操作Redis中的數(shù)據(jù)。事務(wù)支持:Spring Data Redis提供了對(duì)Redis事務(wù)的支持,可以在一系列Redis操作中開(kāi)啟、提交或回滾事務(wù),確保數(shù)據(jù)的一致性和完整性。Pub/Sub消息訂閱/發(fā)布:Spring Data Redis支持Redis的Pub/Sub功能,使應(yīng)用程序能夠通過(guò)訂閱和發(fā)布消息來(lái)實(shí)現(xiàn)解耦和異步通信。緩存支持:Spring Data Redis與Spring緩存抽象集成,使得可以輕松地使用Redis作為緩存提供器,提高應(yīng)用程序的性能和響應(yīng)速度。連接池管理:Spring Data Redis提供了連接池管理功能,通過(guò)連接池可以有效地管理和復(fù)用Redis連接,減少連接的創(chuàng)建和銷毀開(kāi)銷,提高性能和資源利用率。
1、引入pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
2、配置RedisTemplate
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@Configuration
public class RedisTemplateConfig {
@Bean("redisTemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 設(shè)置連接工廠
template.setConnectionFactory(connectionFactory);
// 設(shè)置序列化方式
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key序列化
template.setKeySerializer(stringRedisSerializer);
// value序列化
template.setValueSerializer(getJackson2JsonRedisSerializer());
// Hash key序列化
template.setHashKeySerializer(stringRedisSerializer);
// Hash value序列化
template.setHashValueSerializer(getJackson2JsonRedisSerializer());
template.afterPropertiesSet();
return template;
}
/**
* 緩存管理器
*
* @param redisConnectionFactory
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig();
// 設(shè)置緩存管理器管理
defaultCacheConfig = defaultCacheConfig
// 緩存的默認(rèn)過(guò)期時(shí)間:
.entryTtl(Duration.ofSeconds(36000))
// 設(shè)置 key為string序列化
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
// 設(shè)置value為json序列化
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(getJackson2JsonRedisSerializer()))
// 不緩存空值
.disableCachingNullValues();
Set<String> cacheNames = new HashSet<>();
// 對(duì)每個(gè)緩存空間應(yīng)用不同的配置
Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(defaultCacheConfig)
.initialCacheNames(cacheNames)
.withInitialCacheConfigurations(configMap)
.build();
}
/**
* 獲取Jackson2JsonRedisSerializer序列化對(duì)象
*
* @return o
*/
private Jackson2JsonRedisSerializer<Object> getJackson2JsonRedisSerializer() {
/* 明文存取 */
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
//指定要序列化的域,field,get和set,以及修飾符范圍,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jackson2JsonRedisSerializer.setObjectMapper(om);
return jackson2JsonRedisSerializer;
}
}
3、配置yml
3.1、單機(jī)配置
spring:
redis:
# Redis數(shù)據(jù)庫(kù)索引(默認(rèn)為0)
database: 0
# 連接地址
host: 127.0.0.1
#端口號(hào)
port: 6379
##連接超時(shí)時(shí)間
timeout: 3600ms
#密碼
password:
lettuce:
pool:
# 連接池最大連接數(shù)(使用負(fù)值表示沒(méi)有限制)
max-active: 8
# 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒(méi)有限制)
max-wait: -1ms
# 連接池中的最大空閑連接
max-idle: 8
# 連接池中的最小空閑連接
min-idle: 1
#關(guān)閉超時(shí)
shutdown-timeout: 500ms
3.2、集群配置
spring:
redis:
cluster:
nodes:
- 127.0.0.1:7001
- 127.0.0.1:7002
- 127.0.0.1:7003
- 127.0.0.1:7004
- 127.0.0.1:7005
- 127.0.0.1:7006
#連接超時(shí)時(shí)間
timeout: 3600ms
#密碼
password:
lettuce:
pool:
# 連接池最大連接數(shù)(使用負(fù)值表示沒(méi)有限制)
max-active: 8
# 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒(méi)有限制)
max-wait: -1ms
# 連接池中的最大空閑連接
max-idle: 8
# 連接池中的最小空閑連接
min-idle: 1
#關(guān)閉超時(shí)
shutdown-timeout: 500ms
4、集成使用
@RestController
public class Controller {
@Resource
private RedisTemplate redisTemplate;
@RequestMapping("redis")
public String redis() {
// 測(cè)試redis
String key = "uid";
String value = "測(cè)試用戶";
// 設(shè)置值
redisTemplate.boundValueOps(key).set(value);
// 取出值
Object obj = redisTemplate.opsForValue().get(key);
System.out.println("取出值為:" + obj);
return "操作成功";
}
}
5、工具類封裝及使用
實(shí)際開(kāi)發(fā)中,使用redis的場(chǎng)景會(huì)比較多,可以將reidsTemplate的操作封裝為工具類,代碼如下:
5.1、工具封裝
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Component
public class RedisUtils {
private static RedisTemplate redisTemplate = null;
public RedisUtils(RedisTemplate redisTemplate) {
RedisUtils.redisTemplate = redisTemplate;
}
public static RedisTemplate getRedisTemplate() {
return redisTemplate;
}
/**
* 指定緩存失效時(shí)間
*
* @param key 鍵
* @param time 時(shí)間(秒)
* @return
*/
public static boolean expire(String key, long time, TimeUnit unit) {
try {
if (time > 0) {
redisTemplate.expire(key, time, unit);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根據(jù)key 獲取過(guò)期時(shí)間
*
* @param key 鍵 不能為null
* @return 時(shí)間(秒) 返回0代表為永久有效
*/
public static long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 根據(jù)key 獲取過(guò)期時(shí)間
*
* @param key 鍵 不能為null
* @return TimeUnit
*/
public static long getExpire(String key, TimeUnit timeUnit) {
return redisTemplate.getExpire(key, timeUnit);
}
/**
* 判斷key是否存在
*
* @param key 鍵
* @return true 存在 false不存在
*/
public static boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 刪除緩存
*
* @param key 可以傳一個(gè)值 或多個(gè)
*/
public static void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
/**
* 普通緩存獲取
*
* @param key 鍵
* @return 值
*/
public static Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通緩存放入
*
* @param key 鍵
* @param value 值
* @return true成功 false失敗
*/
public static boolean set(String key, Object value) {
try {
redisTemplate.boundValueOps(key).set(value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 將值 value 關(guān)聯(lián)到 key ,并將 key 的過(guò)期時(shí)間設(shè)為 timeout
*
* @param key
* @param value
* @param timeout 過(guò)期時(shí)間
* @param unit 時(shí)間單位, 天:TimeUnit.DAYS 小時(shí):TimeUnit.HOURS 分鐘:TimeUnit.MINUTES
* 秒:TimeUnit.SECONDS 毫秒:TimeUnit.MILLISECONDS
*/
public static boolean setEx(String key, Object value, long timeout, TimeUnit unit) {
try {
set(key, value);
if (timeout > 0) {
expire(key, timeout, unit);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一張hash表中放入數(shù)據(jù),如果不存在將創(chuàng)建
*
* @param key 鍵
* @param item 項(xiàng)
* @param value 值
* @return true 成功 false失敗
*/
public static boolean hset(String key, String item, Object value) {
try {
redisTemplate.boundHashOps(key).put(item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public static boolean hset(String key, Map<String, String> map) {
try {
redisTemplate.boundHashOps(key).putAll(map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 將值 value 關(guān)聯(lián)到 key ,并將 key 的過(guò)期時(shí)間設(shè)為 timeout
*
* @param key
* @param value
* @param timeout 過(guò)期時(shí)間
* @param unit 時(shí)間單位, 天:TimeUnit.DAYS 小時(shí):TimeUnit.HOURS 分鐘:TimeUnit.MINUTES
* 秒:TimeUnit.SECONDS 毫秒:TimeUnit.MILLISECONDS
*/
public static boolean hSetEx(String key, String item, Object value, long timeout, TimeUnit unit) {
try {
hset(key, item, value);
if (timeout > 0) {
expire(key, timeout, unit);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 獲取所有給定字段的值
*
* @param key
* @return
*/
public static Map<Object, Object> hGetAll(String key) {
return redisTemplate.boundHashOps(key).entries();
}
/**
* 獲取所有哈希表中的字段
*
* @param key
* @return
*/
public static Set<Object> hKeys(String key) {
return redisTemplate.boundHashOps(key).keys();
}
/**
* 獲取哈希表中字段的數(shù)量
*
* @param key
* @return
*/
public static Long hSize(String key) {
return redisTemplate.boundHashOps(key).size();
}
/**
* 獲取哈希表中所有值
*
* @param key
* @return
*/
public static List<Object> hValues(String key) {
return redisTemplate.boundHashOps(key).values();
}
/**
* 向一張hash表中讀取數(shù)據(jù)
*/
public static Object hget(String key, String item) {
try {
return redisTemplate.boundHashOps(key).get(item);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 刪除hash表中的值
*
* @param key 鍵 不能為null
* @param item 項(xiàng) 可以使多個(gè) 不能為null
*/
public static void hdel(String key, Object... item) {
redisTemplate.boundHashOps(key).delete(item);
}
/**
* 判斷hash表中是否有該項(xiàng)的值
*
* @param key 鍵 不能為null
* @param item 項(xiàng) 不能為null
* @return true 存在 false不存在
*/
public static boolean hHasKey(String key, String item) {
return redisTemplate.boundHashOps(key).hasKey(item);
}
/**
* 遞增
*
* @param key 鍵
* // * @param by 要增加幾(大于0)
* @return
*/
public static long incr(String key, long increment) {
if (increment < 0) {
throw new RuntimeException("遞增因子必須大于0");
}
return redisTemplate.boundValueOps(key).increment(increment);
}
/**
* 為哈希表 key 中的指定字段的整數(shù)值加上增量 increment
*
* @param key
* @param field
* @param increment
* @return
*/
public static long hIncrBy(String key, Object field, long increment) {
if (increment < 0) {
throw new RuntimeException("遞增因子必須大于0");
}
return redisTemplate.boundHashOps(key).increment(field, increment);
}
}
5.2、封裝使用
通過(guò)工具類直接操作Redis
@RestController
public class Controller {
@RequestMapping("redis")
public String redis() {
// 測(cè)試redis
String key = "uid";
String value = "測(cè)試用戶";
// 設(shè)置值
RedisUtils.set(key, value);
// 取出值
Object obj = RedisUtils.get(key);
System.out.println("取出值為:" + obj);
return "操作成功";
}
}
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot+MyBatisPlus+Vue 前后端分離項(xiàng)目快速搭建過(guò)程(前端篇)
這篇文章主要介紹了SpringBoot+MyBatisPlus+Vue 前后端分離項(xiàng)目快速搭建過(guò)程(前端篇),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-05-05
Java基于jdbc連接mysql數(shù)據(jù)庫(kù)操作示例
這篇文章主要介紹了Java基于jdbc連接mysql數(shù)據(jù)庫(kù)操作,結(jié)合完整實(shí)例形式分析了java使用jdbc連接mysql數(shù)據(jù)庫(kù)的具體步驟與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-07-07
SpringBoot3使用Jasypt加密數(shù)據(jù)庫(kù)用戶名、密碼等敏感信息
使用Jasypt(Java Simplified Encryption)進(jìn)行數(shù)據(jù)加密和解密主要涉及幾個(gè)步驟,包括引入依賴、配置加密密碼、加密敏感信息、將加密信息存儲(chǔ)到配置文件中,以下是詳細(xì)的使用說(shuō)明,需要的朋友可以參考下2024-07-07
Java使用EasyExcel實(shí)現(xiàn)百萬(wàn)數(shù)據(jù)導(dǎo)出的最佳實(shí)踐指南
這篇文章主要為大家詳細(xì)介紹了Java如何使用EasyExcel實(shí)現(xiàn)百萬(wàn)數(shù)據(jù)導(dǎo)出功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解下2026-01-01

