以下是 Redis 除了數據類型外的核心功能 的詳細說明,包含事務、流水線、發布/訂閱、Lua 腳本的完整代碼示例和表格總結:
1. Redis 事務(Transactions)
功能描述
事務通過 MULTI
和 EXEC
命令將一組命令打包執行,保證命令的原子性(非嚴格原子性)。事務中的命令會被順序執行,但中間可能被其他客戶端命令插入。
代碼示例
@Service
public class RedisTransactionService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;// 使用事務操作public void transactionExample() {redisTemplate.multi(); // 開啟事務try {// 添加多個命令到事務隊列redisTemplate.opsForValue().set("key1", "value1");redisTemplate.opsForValue().increment("counter", 1);// 提交事務List<Object> results = redisTemplate.exec();System.out.println("事務執行結果:" + results);} catch (Exception e) {redisTemplate.discard(); // 回滾事務throw e;}}
}
注意事項
- 事務中的命令若失敗,后續命令仍會執行。
- 使用
exec()
提交后,返回所有命令的執行結果列表。
2. Redis 流水線(Pipeline)
功能描述
流水線將多個命令批量發送到 Redis 服務器,減少網絡往返延遲,提升性能。適用于批量操作(如批量讀寫)。
代碼示例
@Service
public class RedisPipelineService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;// 使用流水線批量操作public void pipelineExample() {redisTemplate.executePipelined((RedisConnection connection) -> {connection.set("key1".getBytes(), "value1".getBytes());connection.set("key2".getBytes(), "value2".getBytes());connection.set("key3".getBytes(), "value3".getBytes());return null;});}
}
注意事項
- 流水線通過
executePipelined
方法實現,需操作底層RedisConnection
。 - 批量操作需自行處理字節序列化。
3. Redis 發布/訂閱(Pub/Sub)
功能描述
用于實時消息通信:
- 發布者:向頻道(channel)發送消息。
- 訂閱者:監聽指定頻道的消息。
代碼示例
3.1 發布者
@Service
public class RedisPublisherService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;// 發布消息到頻道public void publishMessage(String channel, String message) {redisTemplate.convertAndSend(channel, message);}
}
3.2 訂閱者
@Configuration
public class RedisSubscriberConfig {@Beanpublic RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(connectionFactory);container.addMessageListener(new MessageListener() {@Overridepublic void onMessage(Message message, byte[] pattern) {String channel = new String(message.getChannel());String payload = new String(message.getBody());System.out.println("收到消息:頻道[" + channel + "],內容[" + payload + "]");}}, new PatternTopic("channel:*")); // 訂閱所有以 "channel:" 開頭的頻道return container;}
}
注意事項
- 需配置
RedisMessageListenerContainer
監聽消息。 - 消息不會持久化,客戶端斷開后未接收的消息會丟失。
4. Redis Lua 腳本(Lua Scripting)
功能描述
通過 Lua 腳本實現 原子性操作,適用于需要嚴格一致性的場景(如分布式鎖、庫存扣減)。Lua 腳本在 Redis 服務端單線程執行,確保原子性。
代碼示例
4.1 示例腳本:庫存扣減
-- Lua 腳本:扣減庫存,僅當庫存大于0時扣減
local stock = tonumber(redis.call("GET", KEYS[1]))
if stock and stock > 0 thenredis.call("DECR", KEYS[1])return stock - 1
elsereturn -1 -- 庫存不足
end
4.2 Spring Boot 調用 Lua 腳本
@Service
public class RedisLuaService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;// 執行 Lua 腳本(庫存扣減)public Long deductStock(String stockKey) {DefaultRedisScript<Long> script = new DefaultRedisScript<>();script.setScriptText(loadLuaScript("deduct_stock.lua")); // 加載腳本內容script.setResultType(Long.class);return redisTemplate.execute(script, Collections.singletonList(stockKey), new Object[]{});}// 加載 Lua 腳本內容(示例)private String loadLuaScript(String scriptName) {// 實際開發中可從文件或資源加載return "local stock = tonumber(redis.call('GET', KEYS[1])) ..."; // 省略腳本內容}
}
注意事項
- 腳本在 Redis 服務端執行,需確保腳本邏輯正確。
- 可通過
SHA1
哈希緩存腳本,減少傳輸開銷。
5. 總結表格
功能 | 描述 | 代碼方法 | 適用場景 |
---|---|---|---|
事務 | 將一組命令打包執行,保證順序性,但非嚴格原子性。 | redisTemplate.multi() 、redisTemplate.exec() | 需要命令順序執行但允許部分失敗的場景。 |
流水線 | 批量發送命令,減少網絡延遲。 | redisTemplate.executePipelined() | 大批量讀寫操作(如批量插入、查詢)。 |
發布/訂閱 | 實時消息通信,支持頻道或模式訂閱。 | redisTemplate.convertAndSend() 、RedisMessageListenerContainer | 實時通知(如訂單狀態更新、聊天消息)。 |
Lua 腳本 | 在 Redis 服務端原子性執行復雜邏輯,確保數據一致性。 | redisTemplate.execute(script, keys, args) | 需要嚴格原子性的操作(如分布式鎖、扣減庫存)。 |
6. 關鍵點總結
-
事務 vs Lua 腳本:
- 事務提供順序執行,但非原子性(中間可能被其他命令中斷)。
- Lua 腳本確保原子性,適合需要嚴格一致性的場景。
-
流水線優化:
- 批量操作時,流水線可顯著提升性能(減少網絡 RTT)。
-
發布/訂閱:
- 適用于實時消息通信,但需注意消息丟失風險(客戶端斷開時未接收的消息會丟失)。
-
Lua 腳本注意事項:
- 腳本在服務端執行,需謹慎設計邏輯(避免死循環或高耗時操作)。
- 可通過
EVALSHA
命令緩存腳本,減少傳輸開銷。
通過合理使用這些功能,可以解決高并發場景下的性能、一致性和實時性挑戰。