使用 Spring Data Redis 實現 Redis 數據存儲詳解
Spring Data Redis 是 Spring 生態中操作 Redis 的核心模塊,它封裝了 Redis 客戶端的底層細節(如 Jedis 或 Lettuce),提供了統一的 API 來操作 Redis 的數據結構。以下是詳細實現步驟:
一、配置 Spring Data Redis
1. 引入依賴
在 pom.xml
中添加依賴(以 Spring Boot 3.x 為例):
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 使用 Lettuce 客戶端(默認) -->
<dependency><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId>
</dependency>
<!-- 可選:連接池(如使用 Jedis) -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>
2. 配置 Redis 連接
在 application.yml
中配置 Redis 服務器信息:
spring:redis:host: localhost # Redis 服務器地址port: 6379 # 默認端口password: 123456 # 密碼(若無則省略)database: 0 # 默認數據庫索引lettuce:pool:max-active: 8 # 最大連接數max-idle: 4 # 最大空閑連接min-idle: 1 # 最小空閑連接
3. 配置 RedisTemplate
自定義 RedisTemplate
序列化方式(避免二進制亂碼):
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);// Key 統一使用字符串序列化template.setKeySerializer(RedisSerializer.string());template.setHashKeySerializer(RedisSerializer.string());// Value 統一使用 JSON 序列化Jackson2JsonRedisSerializer<Object> jsonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);template.setValueSerializer(jsonSerializer);template.setHashValueSerializer(jsonSerializer);// 特殊數據結構的 Value 序列化(根據需求覆蓋)// template.setDefaultSerializer(jsonSerializer); // 可選:全局默認序列化template.afterPropertiesSet();return template;}
}
二、操作 Redis 數據結構
1. String(字符串)
- 用途:存儲簡單鍵值對(如緩存、計數器)。
- 核心方法:
opsForValue()
@Autowired
private RedisTemplate<String, Object> redisTemplate;// 寫入值
redisTemplate.opsForValue().set("user:1:name", "Alice");// 讀取值
String name = (String) redisTemplate.opsForValue().get("user:1:name");// 原子遞增
Long count = redisTemplate.opsForValue().increment("article:100:views");
2. Hash(哈希表)
- 用途:存儲對象字段(如用戶信息)。
- 核心方法:
opsForHash()
// 存儲用戶對象
Map<String, String> user = new HashMap<>();
user.put("name", "Bob");
user.put("age", "25");
redisTemplate.opsForHash().putAll("user:2", user);// 獲取單個字段
String age = (String) redisTemplate.opsForHash().get("user:2", "age");// 更新字段
redisTemplate.opsForHash().put("user:2", "age", "26");// 獲取所有字段
Map<Object, Object> userData = redisTemplate.opsForHash().entries("user:2");
3. List(列表)
- 用途:實現隊列、棧或消息列表。
- 核心方法:
opsForList()
// 左側插入元素
redisTemplate.opsForList().leftPush("task:queue", "task1");// 右側彈出元素(阻塞式)
String task = (String) redisTemplate.opsForList().rightPop("task:queue", 10, TimeUnit.SECONDS);// 獲取列表范圍
List<Object> tasks = redisTemplate.opsForList().range("task:queue", 0, -1);
4. Set(集合)
- 用途:存儲唯一值(如標簽、共同好友)。
- 核心方法:
opsForSet()
// 添加元素
redisTemplate.opsForSet().add("article:100:tags", "tech", "java", "spring");// 判斷元素是否存在
boolean exists = redisTemplate.opsForSet().isMember("article:100:tags", "java");// 求交集
Set<Object> commonTags = redisTemplate.opsForSet().intersect("article:100:tags", "article:101:tags");
5. Sorted Set(有序集合)
- 用途:排行榜、優先級隊列。
- 核心方法:
opsForZSet()
// 添加元素及分數
redisTemplate.opsForZSet().add("leaderboard", "player1", 100.0);
redisTemplate.opsForZSet().add("leaderboard", "player2", 85.5);// 獲取前 10 名
Set<ZSetOperations.TypedTuple<Object>> topPlayers = redisTemplate.opsForZSet().reverseRangeWithScores("leaderboard", 0, 9);// 更新分數
redisTemplate.opsForZSet().incrementScore("leaderboard", "player1", 20.0);
6. HyperLogLog
- 用途:近似統計獨立用戶數(UV)。
- 核心方法:
opsForHyperLogLog()
// 添加元素
redisTemplate.opsForHyperLogLog().add("uv:20231001", "user1", "user2", "user3");// 統計基數
Long uv = redisTemplate.opsForHyperLogLog().size("uv:20231001");
7. Bitmaps
- 用途:位操作(如用戶簽到)。
- 核心方法:
opsForValue().setBit()
// 設置第 5 位為 1(表示用戶 ID=5 已簽到)
redisTemplate.opsForValue().setBit("sign:user:202310", 5, true);// 統計總簽到數
Long count = redisTemplate.execute((RedisCallback<Long>) conn -> conn.bitCount("sign:user:202310".getBytes())
);
8. GEO(地理空間)
- 用途:附近位置查詢。
- 核心方法:
opsForGeo()
// 添加地理位置
redisTemplate.opsForGeo().add("cities", new Point(116.405285, 39.904989), "Beijing");// 查詢距離
Distance distance = redisTemplate.opsForGeo().distance("cities", "Beijing", "Shanghai", Metrics.KILOMETERS);// 附近 100km 內的城市
GeoResults<GeoLocation<Object>> results = redisTemplate.opsForGeo().radius("cities", "Beijing", new Distance(100, Metrics.KILOMETERS));
三、高級功能
1. 事務支持
redisTemplate.execute(new SessionCallback<List<Object>>() {@Overridepublic List<Object> execute(RedisOperations operations) {operations.multi(); // 開啟事務operations.opsForValue().set("key1", "value1");operations.opsForHash().put("hash1", "field", "value");return operations.exec(); // 提交事務}
});
2. 發布訂閱
// 發布消息
redisTemplate.convertAndSend("news", "Breaking news: Spring 6 released!");// 訂閱消息(需定義 MessageListener)
@Bean
public MessageListenerAdapter listenerAdapter(MessageReceiver receiver) {return new MessageListenerAdapter(receiver, "receiveMessage");
}@Bean
public RedisMessageListenerContainer container(RedisConnectionFactory factory,MessageListenerAdapter listener) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(factory);container.addMessageListener(listener, new ChannelTopic("news"));return container;
}
3. 管道操作(批量執行)
List<Object> results = redisTemplate.executePipelined((RedisCallback<Object>) connection -> {connection.stringCommands().set("key1".getBytes(), "value1".getBytes());connection.stringCommands().set("key2".getBytes(), "value2".getBytes());return null;
});
四、測試與驗證
1. 注入 RedisTemplate
@SpringBootTest
public class RedisTest {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Testvoid testString() {redisTemplate.opsForValue().set("testKey", "Hello Redis");assertEquals("Hello Redis", redisTemplate.opsForValue().get("testKey"));}
}
2. 檢查 Redis 連接
@Autowired
private RedisConnectionFactory redisConnectionFactory;@Test
void testConnection() {RedisConnection conn = redisConnectionFactory.getConnection();assertTrue(conn.ping().equals("PONG"));conn.close();
}
五、注意事項
-
序列化一致性
確保所有操作的 Key/Value 序列化方式一致,避免出現亂碼或類型錯誤。 -
連接泄漏
使用@Transactional
或手動關閉連接,避免未釋放的連接耗盡資源。 -
數據淘汰策略
在 Redis 配置中設置maxmemory-policy
(如allkeys-lru
),防止內存溢出。 -
集群模式
若使用 Redis 集群,需在配置中指定所有節點地址:spring:redis:cluster:nodes: host1:6379,host2:6379,host3:6379