Redis作为缓存的常见使用场景包括数据库查询缓存、会话管理、分布式锁、缓存热点数据、计数器和限流等。以下是详细的说明和代码示例:
1. 数据库查询缓存
数据库查询缓存是最常见的使用场景之一,缓存数据库查询结果以减少直接访问数据库的频率,从而提升系统性能。
示例代码:
java
import redis.clients.jedis.Jedis;
import com.fasterxml.jackson.databind.ObjectMapper;
public class DatabaseQueryCache {
private Jedis jedis;
private static final ObjectMapper objectMapper = new ObjectMapper();
public DatabaseQueryCache(Jedis jedis) {
this.jedis = jedis;
}
public <T> T getCachedData(String key, Class<T> clazz, DataProvider<T> provider, int cacheTime) {
try {
// 尝试从缓存中获取数据
String cacheValue = jedis.get(key);
if (cacheValue != null) {
return objectMapper.readValue(cacheValue, clazz);
}
// 如果缓存中没有数据,则从数据源中获取数据
T data = provider.getData();
// 将数据序列化后存储到缓存中,并设置缓存过期时间
jedis.setex(key, cacheTime, objectMapper.writeValueAsString(data));
return data;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public interface DataProvider<T> {
T getData();
}
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
DatabaseQueryCache cache = new DatabaseQueryCache(jedis);
String userId = "123";
String cacheKey = "user:" + userId;
int cacheTime = 3600; // 缓存 1 小时
User user = cache.getCachedData(cacheKey, User.class, () -> {
// 模拟从数据库查询用户数据
return getUserFromDatabase(userId);
}, cacheTime);
System.out.println("User: " + user);
jedis.close();
}
private static User getUserFromDatabase(String userId) {
// 模拟数据库查询
User user = new User();
user.setId(userId);
user.setName("John Doe");
user.setEmail("john.doe@example.com");
return user;
}
static class User {
private String id;
private String name;
private String email;
// Getters and Setters
@Override
public String toString() {
return "User{id='" + id + "', name='" + name + "', email='" + email + "'}";
}
}
}
2. 会话管理
将用户会话信息存储在Redis中,以实现分布式会话管理。这样可以在多个服务器之间共享会话信息,提高系统的可扩展性和高可用性。
示例代码:
java
import redis.clients.jedis.Jedis;
import java.util.UUID;
public class SessionManager {
private Jedis jedis;
public SessionManager(Jedis jedis) {
this.jedis = jedis;
}
public String createSession(String userId) {
String sessionId = UUID.randomUUID().toString();
String key = "session:" + sessionId;
jedis.hset(key, "userId", userId);
jedis.expire(key, 3600); // 会话过期时间为1小时
return sessionId;
}
public String getUserIdBySessionId(String sessionId) {
String key = "session:" + sessionId;
return jedis.hget(key, "userId");
}
public void destroySession(String sessionId) {
String key = "session:" + sessionId;
jedis.del(key);
}
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
SessionManager sessionManager = new SessionManager(jedis);
// 创建会话
String sessionId = sessionManager.createSession("user123");
System.out.println("Session created: " + sessionId);
// 获取用户ID
String userId = sessionManager.getUserIdBySessionId(sessionId);
System.out.println("User ID: " + userId);
// 销毁会话
sessionManager.destroySession(sessionId);
System.out.println("Session destroyed.");
jedis.close();
}
}
3. 分布式锁
Redis提供了便捷的分布式锁功能,用于在分布式系统中实现互斥访问共享资源。
示例代码:
java
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
public class RedisDistributedLock {
private Jedis jedis;
private String lockKey;
private String lockValue;
private int expireTime;
public RedisDistributedLock(Jedis jedis, String lockKey, int expireTime) {
this.jedis = jedis;
this.lockKey = lockKey;
this.expireTime = expireTime;
this.lockValue = String.valueOf(Thread.currentThread().getId());
}
public boolean acquireLock() {
SetParams params = new SetParams().nx().px(expireTime);
String result = jedis.set(lockKey, lockValue, params);
return "OK".equals(result);
}
public boolean releaseLock() {
String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(luaScript, 1, lockKey, lockValue);
return result.equals(1L);
}
public void executeWithLock(Runnable task) {
if (acquireLock()) {
try {
task.run();
} finally {
boolean released = releaseLock();
if (!released) {
System.out.println("Failed to release lock.");
}
}
} else {
System.out.println("Failed to acquire lock, try again later.");
}
}
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
RedisDistributedLock lock = new RedisDistributedLock(jedis, "resource_lock", 10000);
lock.executeWithLock(() -> {
System.out.println("Executing critical section.");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Critical section completed.");
});
jedis.close();
}
}
4. 缓存热点数据
将频繁访问的热点数据缓存到Redis中,以提高响应速度和系统吞吐量。
示例代码:
java
import redis.clients.jedis.Jedis;
import java.util.HashMap;
import java.util.Map;
public class HotDataCache {
private Jedis jedis;
public HotDataCache(Jedis jedis) {
this.jedis = jedis;
}
public Map<String, String> getHotData(String key) {
Map<String, String> data = jedis.hgetAll(key);
if (data.isEmpty()) {
data = fetchDataFromDatabase(key);
jedis.hmset(key, data);
jedis.expire(key, 3600); // 设置缓存过期时间1小时
}
return data;
}
private Map<String, String> fetchDataFromDatabase(String key) {
// 模拟从数据库获取热点数据
Map<String, String> data = new HashMap<>();
data.put("field1", "value1");
data.put("field2", "value2");
return data;
}
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
HotDataCache cache = new HotDataCache(jedis);
String key = "hot_data:123";
Map<String, String> data = cache.getHotData(key);
System.out.println("Hot data: " + data);
jedis.close();
}
}
5. 计数器和限流
使用Redis的原子操作实现计数器和限流功能,如实现API请求限流、访问计数等。
示例代码:
java
import redis.clients.jedis.Jedis;
public class RateLimiter {
private Jedis jedis;
private String key;
private int limit;
private int expireTime;
public RateLimiter(Jedis jedis, String key, int limit, int expireTime) {
this.jedis = jedis;
this.key = key;
this.limit = limit;
this.expireTime = expireTime;
}
public boolean isAllowed() {
long count = jedis.incr(key);
if (count == 1) {
jedis.expire(key, expireTime); // 设置过期时间
}
return count <= limit;
}
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
RateLimiter limiter = new RateLimiter(jedis, "api_rate_limiter", 100, 60); // 每分钟限制100次请求
for (int i = 0; i < 120; i++) {
if (limiter.isAllowed()) {
System.out.println("Request " + (i + 1) + ": allowed");
} else {
System.out.println("Request " + (i