概述
Redis(Remote Dictionary Server)是一个开源的内存数据库,也可以作为缓存、消息队列和会话管理工具等使用。Redis 支持多种数据结构,包括字符串、列表、集合、有序集合、哈希表等,提供了丰富的数据操作功能,如增删改查、事务、发布订阅等。
redis的特性
高性能: Redis 数据存储在内存中,读写速度非常快,适合高并发的场景。
丰富的数据结构: Redis 支持多种数据结构,可以满足各种数据存储和处理需求。
持久化: Redis 支持持久化功能,可以将内存中的数据保存到磁盘上,以防止数据丢失。
高可用性: Redis 支持主从复制和哨兵机制,可以实现高可用性和自动故障转移。
丰富的功能: Redis 提供了丰富的功能和命令,如事务、发布订阅、Lua 脚本、过期键等。
灵活性: Redis 的配置和部署非常灵活,可以根据需求进行定制和扩展。
redis的应用场景
缓存: 可以作为缓存系统,存储热点数据,加速数据访问速度。
会话管理: 可以用于存储用户会话信息,实现分布式会话管理。
消息队列: 发布订阅功能可以用于构建消息队列系统,实现异步消息传递。
计数器: 可以方便地实现各种计数功能,如网站访问量统计、商品库存计数、消息计数等,而且 Redis 提供的原子操作保证了计数器操作的线程安全性。
分布式锁: 可以用于实现分布式锁,保证多个节点之间的数据一致性。
实时排行榜: 有序集合和计数器可以用于实现实时排行榜功能,如热门商品排行、热门搜索排行等。
redis缓存示例
缓存数据
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private RedisTemplate<String, User> redisTemplate;
public User getUserById(Long id) {
// 先从缓存中查询用户信息
String key = "user:" + id;
User user = redisTemplate.opsForValue().get(key);
if (user == null) {
// 如果缓存中不存在,则从数据库中查询
user = userRepository.findById(id).orElse(null);
if (user != null) {
// 将查询结果存储到缓存中
redisTemplate.opsForValue().set(key, user);
}
}
return user;
}
}
redis会话管理示例
登录/验证会话以及退出服务
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Service
public class UserService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
public String login(String username, String password) {
// 模拟登录验证
if ("admin".equals(username) && "password".equals(password)) {
// 生成一个随机的 token 作为用户的会话 ID
String token = UUID.randomUUID().toString();
// 将用户的会话信息存储在 Redis 中,设置过期时间为 30 分钟
redisTemplate.opsForValue().set(token, username, 30, TimeUnit.MINUTES);
return token;
} else {
return null;
}
}
public boolean checkPermission(String token) {
// 根据 token 在 Redis 中查询用户的会话信息
String username = redisTemplate.opsForValue().get(token);
return username != null;
}
public void logout(String token) {
// 从 Redis 中删除用户的会话信息
redisTemplate.delete(token);
}
}
redis消息队列示例
在 Redis 中实现消息队列通常使用 Redis 的发布与订阅(Pub/Sub)功能,它可以用于实现简单的消息发布和订阅模式,用于实现生产者和消费者之间的消息通信
首先,我们需要创建一个消息生产者,用于发布消息到 Redis 频道中:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
@Component
public class MessageProducer {
@Autowired
private RedisTemplate<String, String> redisTemplate;
public void sendMessage(String channel, String message) {
redisTemplate.convertAndSend(channel, message);
}
}
接下来,我们创建一个消息消费者,用于订阅 Redis 频道并接收消息:
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Component;
@Component
public class MessageConsumer implements MessageListener {
@Override
public void onMessage(Message message, byte[] pattern) {
System.out.println("Received message: " + message.toString());
}
}
最后,我们需要配置 Redis 频道的订阅者,并将消息消费者注册到 Redis 频道上:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
@Configuration
public class RedisConfig {
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory,
MessageConsumer messageConsumer) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(messageConsumer, new ChannelTopic("my_channel"));
return container;
}
}
我们通过 RedisMessageListenerContainer 来创建消息监听容器,并将消息消费者注册到 Redis 频道 "my_channel" 上。
现在,当消息生产者调用 sendMessage() 方法发送消息到 Redis 频道时,消息消费者就会收到并处理该消息。
redis分布式锁示例
Redis 可以通过设置键值对的方式来实现分布式锁,具体方法如下:
使用 SETNX(SET if Not eXists)命令来尝试获取锁。如果返回值为 1,表示获取锁成功,即锁不存在;如果返回值为 0,表示获取锁失败,即锁已经被其他客户端持有。
如果获取锁成功,设置一个过期时间,防止锁永远不被释放导致死锁。可以使用 SETEX 或者 PEXPIRE 命令来设置键的过期时间。
在业务处理完成后,通过 DEL 命令来释放锁。
示例:
import redis.clients.jedis.Jedis;
public class DistributedLock {
private static final String LOCK_KEY = "my_lock";
private static final int LOCK_EXPIRE_TIME_SECONDS = 30;
private Jedis jedis;
public DistributedLock() {
jedis = new Jedis("localhost");
}
public boolean acquireLock() {
long result = jedis.setnx(LOCK_KEY, "1");
if (result == 1) {
jedis.expire(LOCK_KEY, LOCK_EXPIRE_TIME_SECONDS);
return true;
}
return false;
}
public void releaseLock() {
jedis.del(LOCK_KEY);
}
public void close() {
jedis.close();
}
public static void main(String[] args) {
DistributedLock lock = new DistributedLock();
try {
if (lock.acquireLock()) {
System.out.println("Lock acquired successfully!");
// 这里可以执行需要加锁保护的业务逻辑
} else {
System.out.println("Failed to acquire lock!");
}
} finally {
lock.releaseLock();
lock.close();
}
}
}