Redis与Java集成实战:从入门到高级应用
概述
Redis是一个开源的高性能键值对存储系统,它支持多种数据结构,包括字符串、哈希、列表、集合和有序集合等。作为内存数据库,Redis提供了极高的读写速度,使其成为缓存、会话存储和消息队列等场景的理想选择。本文将深入探讨Redis与Java的集成,从基础概念到高级应用,为Java开发者提供全面的Redis使用指南。
目录
Redis简介与核心特性
Redis安装与配置
Java连接Redis:Jedis与Lettuce
Redis数据结构与Java操作
Redis事务与管道
Redis发布订阅模式
Redis与Spring集成
Redis高级特性:持久化与集群
Redis性能优化与最佳实践
实战案例:构建高性能缓存系统
1. Redis简介与核心特性
Redis(Remote Dictionary Server)是一个基于键值对的内存数据库,具有以下核心特性:
高性能:数据存储在内存中,读写速度极快
丰富的数据结构:支持字符串、哈希、列表、集合、有序集合等
持久化:支持RDB和AOF两种持久化方式
高可用:通过主从复制和哨兵模式实现高可用
分布式:支持集群模式,可水平扩展
2. Redis安装与配置
2.1 Linux安装
bash
# 下载Redis wget http://download.redis.io/releases/redis-6.2.6.tar.gz tar xzf redis-6.2.6.tar.gz cd redis-6.2.6# 编译安装 make make install# 启动Redis服务器 redis-server# 启动Redis客户端 redis-cli
2.2 Docker安装
bash
# 拉取Redis镜像 docker pull redis# 运行Redis容器 docker run --name my-redis -d -p 6379:6379 redis# 连接Redis docker exec -it my-redis redis-cli
2.3 基本配置
Redis配置文件通常位于/etc/redis/redis.conf
,以下是一些重要配置项:
conf
# 绑定IP地址 bind 127.0.0.1# 端口号 port 6379# 持久化配置 save 900 1 save 300 10 save 60 10000# 最大内存限制 maxmemory 100mb# 内存淘汰策略 maxmemory-policy allkeys-lru
3. Java连接Redis:Jedis与Lettuce
3.1 Jedis客户端
Jedis是Redis的官方Java客户端之一,使用简单直接。
Maven依赖
xml
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>4.0.1</version> </dependency>
基本使用
java
import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig;public class JedisExample {public static void main(String[] args) {// 创建连接池配置JedisPoolConfig poolConfig = new JedisPoolConfig();poolConfig.setMaxTotal(10);poolConfig.setMaxIdle(5);poolConfig.setMinIdle(1);// 创建连接池JedisPool jedisPool = new JedisPool(poolConfig, "localhost", 6379);// 从连接池获取连接try (Jedis jedis = jedisPool.getResource()) {// 设置键值对jedis.set("key", "value");// 获取值String value = jedis.get("key");System.out.println("Value: " + value);// 删除键jedis.del("key");}// 关闭连接池jedisPool.close();} }
3.2 Lettuce客户端
Lettuce是另一个流行的Redis Java客户端,基于Netty实现,支持异步和响应式编程。
Maven依赖
xml
<dependency><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId><version>6.1.8.RELEASE</version> </dependency>
基本使用
java
import io.lettuce.core.RedisClient; import io.lettuce.core.api.StatefulRedisConnection; import io.lettuce.core.api.sync.RedisCommands;public class LettuceExample {public static void main(String[] args) {// 创建Redis客户端RedisClient redisClient = RedisClient.create("redis://localhost:6379");// 创建连接StatefulRedisConnection<String, String> connection = redisClient.connect();// 获取同步命令接口RedisCommands<String, String> commands = connection.sync();// 执行命令commands.set("key", "value");String value = commands.get("key");System.out.println("Value: " + value);commands.del("key");// 关闭连接和客户端connection.close();redisClient.shutdown();} }
4. Redis数据结构与Java操作
4.1 字符串(String)
java
public class StringOperations {private Jedis jedis;public StringOperations(Jedis jedis) {this.jedis = jedis;}// 设置值public void setValue(String key, String value) {jedis.set(key, value);}// 获取值public String getValue(String key) {return jedis.get(key);}// 设置带过期时间的值public void setValueWithExpire(String key, String value, int seconds) {jedis.setex(key, seconds, value);}// 自增操作public long increment(String key) {return jedis.incr(key);}// 自减操作public long decrement(String key) {return jedis.decr(key);} }
4.2 哈希(Hash)
java
public class HashOperations {private Jedis jedis;public HashOperations(Jedis jedis) {this.jedis = jedis;}// 设置哈希字段值public void setField(String key, String field, String value) {jedis.hset(key, field, value);}// 获取哈希字段值public String getField(String key, String field) {return jedis.hget(key, field);}// 获取所有字段和值public Map<String, String> getAllFields(String key) {return jedis.hgetAll(key);}// 删除字段public long deleteField(String key, String... fields) {return jedis.hdel(key, fields);}// 检查字段是否存在public boolean fieldExists(String key, String field) {return jedis.hexists(key, field);} }
4.3 列表(List)
java
public class ListOperations {private Jedis jedis;public ListOperations(Jedis jedis) {this.jedis = jedis;}// 从左端推入元素public long pushLeft(String key, String... values) {return jedis.lpush(key, values);}// 从右端推入元素public long pushRight(String key, String... values) {return jedis.rpush(key, values);}// 从左端弹出元素public String popLeft(String key) {return jedis.lpop(key);}// 从右端弹出元素public String popRight(String key) {return jedis.rpop(key);}// 获取列表范围public List<String> getRange(String key, long start, long end) {return jedis.lrange(key, start, end);}// 获取列表长度public long getLength(String key) {return jedis.llen(key);} }
4.4 集合(Set)
java
public class SetOperations {private Jedis jedis;public SetOperations(Jedis jedis) {this.jedis = jedis;}// 添加元素public long add(String key, String... members) {return jedis.sadd(key, members);}// 移除元素public long remove(String key, String... members) {return jedis.srem(key, members);}// 获取所有成员public Set<String> getAllMembers(String key) {return jedis.smembers(key);}// 判断元素是否存在public boolean isMember(String key, String member) {return jedis.sismember(key, member);}// 获取集合大小public long getSize(String key) {return jedis.scard(key);}// 求交集public Set<String> intersect(String... keys) {return jedis.sinter(keys);}// 求并集public Set<String> union(String... keys) {return jedis.sunion(keys);}// 求差集public Set<String> difference(String... keys) {return jedis.sdiff(keys);} }
4.5 有序集合(Sorted Set)
java
public class SortedSetOperations {private Jedis jedis;public SortedSetOperations(Jedis jedis) {this.jedis = jedis;}// 添加元素public long add(String key, double score, String member) {return jedis.zadd(key, score, member);}// 获取元素分数public Double getScore(String key, String member) {return jedis.zscore(key, member);}// 获取排名(从小到大)public Long getRank(String key, String member) {return jedis.zrank(key, member);}// 获取排名(从大到小)public Long getReverseRank(String key, String member) {return jedis.zrevrank(key, member);}// 获取范围内的元素(按分数从小到大)public Set<String> getRangeByScore(String key, double min, double max) {return jedis.zrangeByScore(key, min, max);}// 获取范围内的元素(按分数从大到小)public Set<String> getReverseRangeByScore(String key, double max, double min) {return jedis.zrevrangeByScore(key, max, min);}// 增加元素分数public Double incrementScore(String key, String member, double increment) {return jedis.zincrby(key, increment, member);} }
5. Redis事务与管道
5.1 事务操作
Redis事务通过MULTI、EXEC、DISCARD和WATCH命令实现,可以保证一系列命令的原子性执行。
java
public class TransactionExample {private Jedis jedis;public TransactionExample(Jedis jedis) {this.jedis = jedis;}// 基本事务操作public void basicTransaction() {// 开始事务Transaction transaction = jedis.multi();try {// 添加多个命令transaction.set("key1", "value1");transaction.set("key2", "value2");transaction.set("key3", "value3");// 执行事务transaction.exec();} catch (Exception e) {// 取消事务transaction.discard();e.printStackTrace();}}// 使用WATCH实现乐观锁public boolean watchExample(String key, String expectedValue, String newValue) {// 监视键jedis.watch(key);// 检查当前值是否符合预期String currentValue = jedis.get(key);if (!expectedValue.equals(currentValue)) {jedis.unwatch();return false;}// 开始事务Transaction transaction = jedis.multi();transaction.set(key, newValue);// 执行事务,如果键被修改则返回nullList<Object> results = transaction.exec();return results != null;} }
5.2 管道操作
Redis管道可以一次性发送多个命令,减少网络往返时间,提高性能。
java
public class PipelineExample {private Jedis jedis;public PipelineExample(Jedis jedis) {this.jedis = jedis;}// 基本管道操作public void basicPipeline() {Pipeline pipeline = jedis.pipelined();// 添加多个命令for (int i = 0; i < 1000; i++) {pipeline.set("key" + i, "value" + i);}// 同步所有命令pipeline.sync();}// 管道与事务结合public void pipelineWithTransaction() {Pipeline pipeline = jedis.pipelined();// 开始事务pipeline.multi();// 添加多个命令for (int i = 0; i < 100; i++) {pipeline.set("txKey" + i, "txValue" + i);}// 执行事务pipeline.exec();// 同步所有命令pipeline.sync();} }
6. Redis发布订阅模式
Redis发布订阅模式实现了消息的广播机制,允许多个客户端订阅频道并接收消息。
java
public class PubSubExample {private Jedis jedis;public PubSubExample(Jedis jedis) {this.jedis = jedis;}// 发布消息public void publish(String channel, String message) {jedis.publish(channel, message);}// 订阅频道public void subscribe(String... channels) {JedisPubSub jedisPubSub = new JedisPubSub() {@Overridepublic void onMessage(String channel, String message) {System.out.println("Received message: " + message + " from channel: " + channel);}@Overridepublic void onSubscribe(String channel, int subscribedChannels) {System.out.println("Subscribed to channel: " + channel);}@Overridepublic void onUnsubscribe(String channel, int subscribedChannels) {System.out.println("Unsubscribed from channel: " + channel);}};// 订阅频道(会阻塞当前线程)jedis.subscribe(jedisPubSub, channels);}// 模式订阅public void psubscribe(String... patterns) {JedisPubSub jedisPubSub = new JedisPubSub() {@Overridepublic void onPMessage(String pattern, String channel, String message) {System.out.println("Received message: " + message + " from channel: " + channel + " matching pattern: " + pattern);}@Overridepublic void onPSubscribe(String pattern, int subscribedChannels) {System.out.println("Subscribed to pattern: " + pattern);}@Overridepublic void onPUnsubscribe(String pattern, int subscribedChannels) {System.out.println("Unsubscribed from pattern: " + pattern);}};// 订阅模式(会阻塞当前线程)jedis.psubscribe(jedisPubSub, patterns);} }
7. Redis与Spring集成
7.1 Spring Data Redis配置
Spring Data Redis提供了对Redis的抽象和封装,简化了Redis操作。
Maven依赖
xml
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId> </dependency>
配置类
java
@Configuration @EnableCaching public class RedisConfig {@Beanpublic RedisConnectionFactory redisConnectionFactory() {RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration("localhost", 6379);// 如果有密码// configuration.setPassword(RedisPassword.of("password"));return new LettuceConnectionFactory(configuration);}@Beanpublic RedisTemplate<String, Object> redisTemplate() {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(redisConnectionFactory());// 使用Jackson2JsonRedisSerializer序列化值Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);ObjectMapper objectMapper = new ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);serializer.setObjectMapper(objectMapper);// 使用StringRedisSerializer序列化键template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(serializer);template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(serializer);template.afterPropertiesSet();return template;}@Beanpublic CacheManager cacheManager(RedisConnectionFactory factory) {RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)) // 设置缓存过期时间.disableCachingNullValues(); // 不缓存空值return RedisCacheManager.builder(factory).cacheDefaults(config).transactionAware().build();} }
7.2 使用RedisTemplate
java
@Service public class UserService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;// 使用ValueOperationspublic void setUser(String key, User user) {ValueOperations<String, Object> valueOps = redisTemplate.opsForValue();valueOps.set(key, user);}public User getUser(String key) {ValueOperations<String, Object> valueOps = redisTemplate.opsForValue();return (User) valueOps.get(key);}// 使用HashOperationspublic void setUserHash(String key, User user) {HashOperations<String, String, Object> hashOps = redisTemplate.opsForHash();Map<String, Object> userMap = new HashMap<>();userMap.put("id", user.getId());userMap.put("name", user.getName());userMap.put("email", user.getEmail());hashOps.putAll(key, userMap);}public User getUserHash(String key) {HashOperations<String, String, Object> hashOps = redisTemplate.opsForHash();Map<String, Object> userMap = hashOps.entries(key);User user = new User();user.setId((Long) userMap.get("id"));user.setName((String) userMap.get("name"));user.setEmail((String) userMap.get("email"));return user;}// 使用ListOperationspublic void addToUserList(String key, User user) {ListOperations<String, Object> listOps = redisTemplate.opsForList();listOps.rightPush(key, user);}public List<User> getUserList(String key) {ListOperations<String, Object> listOps = redisTemplate.opsForList();List<Object> userObjects = listOps.range(key, 0, -1);return userObjects.stream().map(obj -> (User) obj).collect(Collectors.toList());} }
7.3 使用Spring Cache注解
java
@Service public class ProductService {@Cacheable(value = "products", key = "#id")public Product getProductById(Long id) {// 模拟数据库查询System.out.println("Getting product from database: " + id);return findProductInDatabase(id);}@CachePut(value = "products", key = "#product.id")public Product updateProduct(Product product) {// 模拟数据库更新System.out.println("Updating product in database: " + product.getId());return updateProductInDatabase(product);}@CacheEvict(value = "products", key = "#id")public void deleteProduct(Long id) {// 模拟数据库删除System.out.println("Deleting product from database: " + id);deleteProductFromDatabase(id);}@Caching(evict = {@CacheEvict(value = "products", key = "#id"),@CacheEvict(value = "productList", allEntries = true)})public void deleteProductAndClearList(Long id) {// 模拟数据库删除System.out.println("Deleting product and clearing list: " + id);deleteProductFromDatabase(id);}// 模拟数据库操作private Product findProductInDatabase(Long id) {// 实际项目中这里会访问数据库Product product = new Product();product.setId(id);product.setName("Product " + id);product.setPrice(100.0 * id);return product;}private Product updateProductInDatabase(Product product) {// 实际项目中这里会更新数据库return product;}private void deleteProductFromDatabase(Long id) {// 实际项目中这里会删除数据库记录} }
8. Redis高级特性:持久化与集群
8.1 持久化配置
Redis提供两种持久化方式:RDB(快照)和AOF(追加文件)。
RDB配置
conf
# 在900秒内至少有1个键被改变时生成快照 save 900 1# 在300秒内至少有10个键被改变时生成快照 save 300 10# 在60秒内至少有10000个键被改变时生成快照 save 60 10000# 快照文件名 dbfilename dump.rdb# 快照文件目录 dir /var/lib/redis
AOF配置
conf
# 开启AOF持久化 appendonly yes# AOF文件名 appendfilename "appendonly.aof"# 持久化策略 # appendfsync always # 每次写操作都同步 appendfsync everysec # 每秒同步一次 # appendfsync no # 由操作系统决定同步时机# AOF重写时是否继续同步 no-appendfsync-on-rewrite no# 自动触发AOF重写的条件 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb
8.2 Redis集群
Redis集群提供数据分片和高可用性,通过分片将数据分布到多个节点上。
集群配置
java
@Configuration public class RedisClusterConfig {@Beanpublic RedisConnectionFactory redisConnectionFactory() {RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();// 添加集群节点clusterConfiguration.addClusterNode(new RedisNode("127.0.0.1", 7000));clusterConfiguration.addClusterNode(new RedisNode("127.0.0.1", 7001));clusterConfiguration.addClusterNode(new RedisNode("127.0.0.1", 7002));clusterConfiguration.addClusterNode(new RedisNode("127.0.0.1", 7003));clusterConfiguration.addClusterNode(new RedisNode("127.0.0.1", 7004));clusterConfiguration.addClusterNode(new RedisNode("127.0.0.1", 7005));// 设置重定向次数clusterConfiguration.setMaxRedirects(5);// 如果有密码// clusterConfiguration.setPassword(RedisPassword.of("password"));return new LettuceConnectionFactory(clusterConfiguration);}@Beanpublic RedisTemplate<String, Object> redisTemplate() {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(redisConnectionFactory());// 设置序列化方式template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(new GenericJackson2JsonRedisSerializer());template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());return template;} }
集群操作
java
@Service public class ClusterService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;// 集群键操作public void clusterOperations() {// 获取集群连接RedisConnectionFactory connectionFactory = redisTemplate.getConnectionFactory();RedisClusterConnection clusterConnection = connectionFactory.getClusterConnection();// 获取集群信息ClusterInfo clusterInfo = clusterConnection.clusterGetClusterInfo();System.out.println("Cluster state: " + clusterInfo.getState());System.out.println("Cluster size: " + clusterInfo.getClusterSize());System.out.println("Slots assigned: " + clusterInfo.getSlotsAssigned());// 获取节点信息Iterable<RedisClusterNode> nodes = clusterConnection.clusterGetNodes();for (RedisClusterNode node : nodes) {System.out.println("Node: " + node.getHost() + ":" + node.getPort() + " - " + node.getType());}// 关闭连接clusterConnection.close();}// 使用RedisTemplate进行跨槽位操作public void crossSlotOperations() {// 使用哈希标签确保相关键在同一个槽位String userKey = "user:{1000}:profile";String userOrdersKey = "user:{1000}:orders";// 这些键会被哈希到同一个槽位,因为使用了相同的哈希标签{1000}redisTemplate.opsForValue().set(userKey, "user profile");redisTemplate.opsForList().rightPush(userOrdersKey, "order1");redisTemplate.opsForList().rightPush(userOrdersKey, "order2");// 执行事务(需要确保所有键在同一个槽位)redisTemplate.execute(new SessionCallback<List<Object>>() {@Overridepublic List<Object> execute(RedisOperations operations) throws DataAccessException {operations.multi();operations.opsForValue().get(userKey);operations.opsForList().range(userOrdersKey, 0, -1);return operations.exec();}});} }
9. Redis性能优化与最佳实践
9.1 性能优化策略
合理使用数据结构:根据场景选择最合适的数据结构
使用管道:批量操作减少网络往返时间
避免大键:单个键的值不宜过大,可考虑分片存储
使用连接池:避免频繁创建和销毁连接
合理配置持久化:根据数据重要性选择RDB或AOF
使用Lua脚本:减少网络传输,保证原子性
9.2 内存优化
java
public class MemoryOptimization {// 使用哈希压缩小对象public void storeUserAsHash(User user) {String key = "user:" + user.getId();Map<String, String> userMap = new HashMap<>();userMap.put("name", user.getName());userMap.put("email", user.getEmail());userMap.put("age", String.valueOf(user.getAge()));// 使用哈希存储比序列化整个对象更节省内存redisTemplate.opsForHash().putAll(key, userMap);}// 使用整数集合优化小集合public void optimizeSmallSets() {// Redis会自动优化小集合的内存使用// 当集合元素较少且都是整数时,会使用更紧凑的整数集合表示// 添加整数元素for (int i = 0; i < 100; i++) {redisTemplate.opsForSet().add("small:int:set", i);}// 添加字符串元素for (int i = 0; i < 100; i++) {redisTemplate.opsForSet().add("small:str:set", "value" + i);}}// 使用字节数组存储二进制数据public void storeBinaryData(byte[] data, String key) {// 直接存储字节数组,避免序列化开销redisTemplate.opsForValue().set(key.getBytes(), data);} }
9.3 监控与诊断
java
public class RedisMonitor {@Autowiredprivate RedisConnectionFactory connectionFactory;// 获取Redis信息public void getRedisInfo() {RedisConnection connection = connectionFactory.getConnection();// 获取服务器信息Properties info = connection.info();for (String key : info.stringPropertyNames()) {System.out.println(key + ": " + info.getProperty(key));}// 获取内存信息Properties memoryInfo = connection.info("memory");System.out.println("Used memory: " + memoryInfo.getProperty("used_memory"));System.out.println("Used memory human: " + memoryInfo.getProperty("used_memory_human"));connection.close();}// 慢查询日志public void getSlowLog() {RedisConnection connection = connectionFactory.getConnection();// 获取慢查询日志List<Map<String, Object>> slowLog = connection.slowLogGet();for (Map<String, Object> entry : slowLog) {System.out.println("Slow query: " + entry.get("command") + ", execution time: " + entry.get("executionTime"));}connection.close();}// 监控键空间public void monitorKeySpace() {RedisConnection connection = connectionFactory.getConnection();// 获取数据库大小Long dbSize = connection.dbSize();System.out.println("Database size: " + dbSize);// 扫描键Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match("*").count(100).build());while (cursor.hasNext()) {byte[] key = cursor.next();System.out.println("Key: " + new String(key));// 获取键的类型DataType type = connection.type(key);System.out.println("Type: " + type);// 获取键的TTLLong ttl = connection.ttl(key);System.out.println("TTL: " + ttl);}cursor.close();connection.close();} }
10. 实战案例:构建高性能缓存系统
10.1 缓存策略设计
java
@Service public class CacheService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Autowiredprivate DatabaseService databaseService;// 缓存穿透保护:使用布隆过滤器或空值缓存public Object getWithPenetrationProtection(String key, Class<?> type) {// 尝试从缓存获取Object value = redisTemplate.opsForValue().get(key);if (value != null) {// 如果是空值标记,返回nullif (value.equals("NULL")) {return null;}return value;}// 从数据库获取value = databaseService.getFromDatabase(key, type);if (value != null) {// 缓存有效数据redisTemplate.opsForValue().set(key, value, 1, TimeUnit.HOURS);} else {// 缓存空值,防止缓存穿透redisTemplate.opsForValue().set(key, "NULL", 5, TimeUnit.MINUTES);}return value;}// 缓存击穿保护:使用互斥锁public Object getWithBreakdownProtection(String key, Class<?> type) {// 尝试从缓存获取Object value = redisTemplate.opsForValue().get(key);if (value != null) {return value;}// 尝试获取分布式锁String lockKey = "lock:" + key;boolean locked = tryLock(lockKey);if (locked) {try {// 双重检查,防止重复查询数据库value = redisTemplate.opsForValue().get(key);if (value != null) {return value;}// 从数据库获取value = databaseService.getFromDatabase(key, type);if (value != null) {// 缓存数据redisTemplate.opsForValue().set(key, value, 1, TimeUnit.HOURS);}return value;} finally {// 释放锁releaseLock(lockKey);}} else {// 等待并重试try {Thread.sleep(100);return getWithBreakdownProtection(key, type);} catch (InterruptedException e) {Thread.currentThread().interrupt();return null;}}}// 缓存雪崩保护:设置不同的过期时间public void setWithAvalancheProtection(String key, Object value) {// 基础过期时间long baseExpire = TimeUnit.MINUTES.toSeconds(30);// 随机偏移量(±5分钟)long randomOffset = ThreadLocalRandom.current().nextLong(-TimeUnit.MINUTES.toSeconds(5), TimeUnit.MINUTES.toSeconds(5));long expireTime = baseExpire + randomOffset;redisTemplate.opsForValue().set(key, value, expireTime, TimeUnit.SECONDS);}// 尝试获取分布式锁private boolean tryLock(String lockKey) {return redisTemplate.opsForValue().setIfAbsent(lockKey, "locked", 10, TimeUnit.SECONDS);}// 释放分布式锁private void releaseLock(String lockKey) {redisTemplate.delete(lockKey);} }
10.2 多级缓存架构
java
@Service @Primary public class MultiLevelCacheService implements CacheService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Autowiredprivate CaffeineCache localCache;@Autowiredprivate DatabaseService databaseService;// 多级缓存:本地缓存 + Redis缓存public Object getMultiLevel(String key, Class<?> type) {// 第一级:本地缓存Object value = localCache.getIfPresent(key);if (value != null) {return value;}// 第二级:Redis缓存value = redisTemplate.opsForValue().get(key);if (value != null) {// 回填本地缓存localCache.put(key, value);return value;}// 第三级:数据库value = databaseService.getFromDatabase(key, type);if (value != null) {// 同时写入Redis和本地缓存redisTemplate.opsForValue().set(key, value, 1, TimeUnit.HOURS);localCache.put(key, value);}return value;}// 缓存更新策略public void updateMultiLevel(String key, Object value) {// 先更新数据库databaseService.updateInDatabase(key, value);// 再删除缓存(延迟双删策略)deleteMultiLevel(key);// 延迟一段时间再次删除CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS).execute(() -> deleteMultiLevel(key));}// 多级缓存删除public void deleteMultiLevel(String key) {// 删除本地缓存localCache.invalidate(key);// 删除Redis缓存redisTemplate.delete(key);}// 缓存预热public void warmUpCache(List<String> keys) {for (String key : keys) {Object value = databaseService.getFromDatabase(key, Object.class);if (value != null) {redisTemplate.opsForValue().set(key, value, 1, TimeUnit.HOURS);localCache.put(key, value);}}} }
10.3 缓存监控与管理
java
@Service public class CacheManagerService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Autowiredprivate CacheManager cacheManager;// 获取缓存统计信息public Map<String, Object> getCacheStats() {Map<String, Object> stats = new HashMap<>();// 获取所有缓存名称Collection<String> cacheNames = cacheManager.getCacheNames();stats.put("cacheCount", cacheNames.size());// 获取每个缓存的统计信息Map<String, Object> cacheStats = new HashMap<>();for (String cacheName : cacheNames) {Cache cache = cacheManager.getCache(cacheName);if (cache instanceof RedisCache) {RedisCache redisCache = (RedisCache) cache;// 这里可以获取更多Redis缓存特定的统计信息cacheStats.put(cacheName, "Redis Cache");} else {cacheStats.put(cacheName, "Other Cache Type");}}stats.put("caches", cacheStats);// 获取Redis内存信息RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();Properties memoryInfo = connection.info("memory");stats.put("usedMemory", memoryInfo.getProperty("used_memory_human"));stats.put("usedMemoryRss", memoryInfo.getProperty("used_memory_rss_human"));connection.close();return stats;}// 清理缓存public void clearCache(String cacheName) {Cache cache = cacheManager.getCache(cacheName);if (cache != null) {cache.clear();}}// 批量清理缓存public void clearCaches(Set<String> cacheNames) {for (String cacheName : cacheNames) {clearCache(cacheName);}}// 获取热点键public List<String> getHotKeys(String pattern) {List<String> hotKeys = new ArrayList<>();RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(pattern).count(100).build());while (cursor.hasNext()) {byte[] key = cursor.next();Long count = connection.getClientList().stream().filter(client -> client.contains(new String(key))).count();if (count > 10) { // 访问次数超过10次认为是热点键hotKeys.add(new String(key));}}cursor.close();connection.close();return hotKeys;} }
总结
本文全面介绍了Redis与Java的集成,从基础概念到高级应用,涵盖了以下内容:
Redis核心特性:高性能、丰富的数据结构、持久化、高可用和分布式支持
Java客户端:Jedis和Lettuce的使用和比较
数据结构操作:字符串、哈希、列表、集合和有序集合的Java操作
高级特性:事务、管道、发布订阅模式的使用
Spring集成:Spring Data Redis的配置和使用,缓存注解的应用
集群与持久化:Redis集群配置和持久化策略
性能优化:内存优化、监控诊断和最佳实践
实战案例:构建高性能缓存系统,包括多级缓存架构和缓存策略
通过本文的学习,Java开发者可以全面掌握Redis的使用,在实际项目中构建高性能、可扩展的缓存和数据存储解决方案。Redis作为内存数据库的领军产品,与Java的结合将为应用系统带来显著的性能提升和架构优化。