一、Redis 基礎概念
Redis(Remote Dictionary Server)是開源的內存鍵值對數據庫,以高性能著稱。它支持多種數據結構(String、Hash、List、Set、ZSet),并提供持久化機制(RDB、AOF)。
核心特點:
內存存儲,讀寫速度極快(單線程處理命令,QPS 可達 10w+)
支持數據持久化,避免重啟數據丟失
提供豐富的數據結構操作
支持主從復制、哨兵模式和集群部署
單線程模型,避免上下文切換開銷
典型應用場景:
緩存(減輕數據庫壓力)
計數器 / 限速器(如點贊數、限流)
消息隊列(基于 List 或 Pub/Sub)
會話存儲(分布式系統共享 Session)
排行榜(ZSet 有序集合)
二、Spring Data Redis 入門
Spring Data Redis 是 Spring 家族的一部分,提供了簡化 Redis 操作的抽象層。
核心組件:
RedisTemplate:操作 Redis 的核心類
StringRedisTemplate:RedisTemplate 的子類,專門處理字符串
RedisConnectionFactory:連接工廠,管理 Redis 連接
RedisSerializer:序列化器,處理數據的序列化與反序列化
快速上手步驟:
添加依賴(Maven)
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置連接信息(application.properties)
properties
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=yourpassword
使用 RedisTemplate 操作數據
java
@Service
public class RedisExampleService {
private final RedisTemplate<String, Object> redisTemplate;
? ? public RedisExampleService(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
? ? // 存儲字符串
public void setString(String key, String value) {
redisTemplate.opsForValue().set(key, value);
}
? ? // 獲取字符串
public String getString(String key) {
return (String) redisTemplate.opsForValue().get(key);
}
? ? // 存儲 Hash
public void setHash(String key, String field, Object value) {
redisTemplate.opsForHash().put(key, field, value);
}
? ? // 獲取 Hash
public Object getHash(String key, String field) {
return redisTemplate.opsForHash().get(key, field);
}
}
三、序列化機制詳解
RedisTemplate 默認使用 JDK 序列化器,會導致存儲的鍵值帶有類信息前綴(如 \xAC\xED\x00\x05t\x00\x03key),可讀性差且占用空間。
推薦配置 JSON 序列化:
java
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
? ? ? ? // 使用 Jackson 2 序列化器處理值
Jackson2JsonRedisSerializer<Object> jsonSerializer =?
new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(
om.getPolymorphicTypeValidator(),?
ObjectMapper.DefaultTyping.NON_FINAL
);
jsonSerializer.setObjectMapper(om);
? ? ? ? // 使用 String 序列化器處理鍵
StringRedisSerializer stringSerializer = new StringRedisSerializer();
template.setKeySerializer(stringSerializer);
template.setHashKeySerializer(stringSerializer);
template.setValueSerializer(jsonSerializer);
template.setHashValueSerializer(jsonSerializer);
? ? ? ? template.afterPropertiesSet();
return template;
}
}
四、緩存注解實戰
Spring Data Redis 提供了基于注解的緩存抽象,簡化緩存操作。
核心注解:
@Cacheable:查詢時先查緩存,沒有則執行方法并緩存結果
@CachePut:強制更新緩存(無論是否存在)
@CacheEvict:清除緩存
@Caching:組合多個緩存注解
@CacheConfig:類級別的緩存配置
示例代碼:
java
@Service
@CacheConfig(cacheNames = "users") // 默認緩存名稱
public class UserService {
? ? @Cacheable(key = "#id") // 緩存鍵為方法參數 id
public User getUserById(Long id) {
System.out.println("查詢數據庫: " + id);
return userRepository.findById(id).orElse(null);
}
? ? @CachePut(key = "#user.id") // 更新緩存
public User updateUser(User user) {
return userRepository.save(user);
}
? ? @CacheEvict(key = "#id") // 清除緩存
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
? ? @Caching(
evict = {
@CacheEvict(key = "#id"),
@CacheEvict(cacheNames = "userList", allEntries = true)
}
)
public void deleteAndFlush(Long id) {
userRepository.deleteById(id);
}
}
五、高級特性與最佳實踐
Redis 事務
java
public void transactionExample() {
redisTemplate.execute(new SessionCallback<List<Object>>() {
@Override
public List<Object> execute(RedisOperations operations) throws DataAccessException {
operations.multi(); // 開啟事務
operations.opsForValue().set("key1", "value1");
operations.opsForValue().increment("counter");
return operations.exec(); // 執行事務
}
});
}
分布式鎖實現
java
public Boolean acquireLock(String lockKey, String requestId, long expireTime) {
return redisTemplate.execute((RedisCallback<Boolean>) connection -> {
JedisCommands commands = (JedisCommands) connection.getNativeConnection();
return "OK".equals(commands.set(lockKey, requestId, "NX", "PX", expireTime));
});
}
public Boolean releaseLock(String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
return redisTemplate.execute((RedisCallback<Boolean>) connection -> {
JedisCommands commands = (JedisCommands) connection.getNativeConnection();
return commands.eval(script, Collections.singletonList(lockKey),?
Collections.singletonList(requestId))
.equals(1L);
});
}
消息發布與訂閱
java
// 發布者
public void publishMessage(String channel, String message) {
redisTemplate.convertAndSend(channel, message);
}
// 訂閱者配置
@Configuration
public class RedisMessageConfig {
@Bean
RedisMessageListenerContainer container(
RedisConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(listenerAdapter, new PatternTopic("chat"));
return container;
}
? ? @Bean
MessageListenerAdapter listenerAdapter(Receiver receiver) {
return new MessageListenerAdapter(receiver, "receiveMessage");
}
}
// 消息接收者
@Component
public class Receiver {
public void receiveMessage(String message) {
System.out.println("收到消息: " + message);
}
}
六、性能優化與監控
連接池配置
properties
spring.redis.lettuce.pool.max-active=8 ? # 最大連接數
spring.redis.lettuce.pool.max-wait=-1ms ?# 獲取連接的最大等待時間
spring.redis.lettuce.pool.max-idle=8 ? ? # 最大空閑連接數
spring.redis.lettuce.pool.min-idle=0 ? ? # 最小空閑連接數
慢查詢日志
properties
# redis.conf 配置
slowlog-log-slower-than 10000 ?# 記錄超過 10ms 的命令
slowlog-max-len 128 ? ? ? ? ? ?# 最多保留 128 條日志
內存優化
合理設置過期時間
使用 Hash 結構減少鍵數量
避免大 Value(建議不超過 10KB)
七、集群與高可用
哨兵模式配置
properties
spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=192.168.1.1:26379,192.168.1.2:26379
spring.redis.password=yourpassword
集群模式配置
properties
spring.redis.cluster.nodes=192.168.1.1:7000,192.168.1.2:7001,192.168.1.3:7002
spring.redis.cluster.max-redirects=3 ?# 最大重定向次數
八、常見問題與解決方案
緩存穿透
空值緩存:查詢不存在時也緩存空結果
布隆過濾器:預先過濾不可能存在的 key
緩存雪崩
過期時間打散:為緩存設置隨機過期時間
多級緩存:本地緩存 + Redis 結合
緩存擊穿
互斥鎖:查詢數據庫時加鎖,保證單線程訪問
永不過期:熱點數據不過期,異步更新
序列化異常
統一序列化方式
確保實體類實現 Serializable 接口
九、總結
Spring Data Redis 提供了強大而靈活的 Redis 操作能力,通過模板類和注解簡化了開發流程。合理使用 Redis 可以顯著提升應用性能,但需要注意分布式環境下的一致性、并發控制等問題。
建議實踐:
優先使用 JSON 序列化
為緩存設置合理的過期時間
對熱點數據進行預加載
監控 Redis 性能指標(內存、QPS、命中率)
生產環境采用集群部署確保高可用