以下是 Redis 除了数据类型外的核心功能 的详细说明,包含事务、流水线、发布/订阅、Lua 脚本的完整代码示例和表格总结:
1. Redis 事务(Transactions)
功能描述
事务通过 MULTI
和 EXEC
命令将一组命令打包执行,保证命令的原子性(非严格原子性)。事务中的命令会被顺序执行,但中间可能被其他客户端命令插入。
代码示例
java
@Service
public class RedisTransactionService {
@Autowired
private 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 服务器,减少网络往返延迟,提升性能。适用于批量操作(如批量读写)。
代码示例
java
@Service
public class RedisPipelineService {
@Autowired
private 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 发布者
java
@Service
public class RedisPublisherService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 发布消息到频道
public void publishMessage(String channel, String message) {
redisTemplate.convertAndSend(channel, message);
}
}
3.2 订阅者
java
@Configuration
public class RedisSubscriberConfig {
@Bean
public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(new MessageListener() {
@Override
public 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
-- Lua 脚本:扣减库存,仅当库存大于0时扣减
local stock = tonumber(redis.call("GET", KEYS[1]))
if stock and stock > 0 then
redis.call("DECR", KEYS[1])
return stock - 1
else
return -1 -- 库存不足
end
4.2 Spring Boot 调用 Lua 脚本
java
@Service
public class RedisLuaService {
@Autowired
private 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
命令缓存脚本,减少传输开销。
通过合理使用这些功能,可以解决高并发场景下的性能、一致性和实时性挑战。