当前位置: 首页 > news >正文

Redis与Java集成实战:从入门到高级应用

概述

Redis是一个开源的高性能键值对存储系统,它支持多种数据结构,包括字符串、哈希、列表、集合和有序集合等。作为内存数据库,Redis提供了极高的读写速度,使其成为缓存、会话存储和消息队列等场景的理想选择。本文将深入探讨Redis与Java的集成,从基础概念到高级应用,为Java开发者提供全面的Redis使用指南。

目录

  1. Redis简介与核心特性

  2. Redis安装与配置

  3. Java连接Redis:Jedis与Lettuce

  4. Redis数据结构与Java操作

  5. Redis事务与管道

  6. Redis发布订阅模式

  7. Redis与Spring集成

  8. Redis高级特性:持久化与集群

  9. Redis性能优化与最佳实践

  10. 实战案例:构建高性能缓存系统

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 性能优化策略

  1. 合理使用数据结构:根据场景选择最合适的数据结构

  2. 使用管道:批量操作减少网络往返时间

  3. 避免大键:单个键的值不宜过大,可考虑分片存储

  4. 使用连接池:避免频繁创建和销毁连接

  5. 合理配置持久化:根据数据重要性选择RDB或AOF

  6. 使用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的集成,从基础概念到高级应用,涵盖了以下内容:

  1. Redis核心特性:高性能、丰富的数据结构、持久化、高可用和分布式支持

  2. Java客户端:Jedis和Lettuce的使用和比较

  3. 数据结构操作:字符串、哈希、列表、集合和有序集合的Java操作

  4. 高级特性:事务、管道、发布订阅模式的使用

  5. Spring集成:Spring Data Redis的配置和使用,缓存注解的应用

  6. 集群与持久化:Redis集群配置和持久化策略

  7. 性能优化:内存优化、监控诊断和最佳实践

  8. 实战案例:构建高性能缓存系统,包括多级缓存架构和缓存策略

通过本文的学习,Java开发者可以全面掌握Redis的使用,在实际项目中构建高性能、可扩展的缓存和数据存储解决方案。Redis作为内存数据库的领军产品,与Java的结合将为应用系统带来显著的性能提升和架构优化。


文章转载自:

http://B0HDigML.jhrkm.cn
http://KKeH9717.jhrkm.cn
http://foTixjJ2.jhrkm.cn
http://zH324pDj.jhrkm.cn
http://V6yF8Ev1.jhrkm.cn
http://fVP4n473.jhrkm.cn
http://tCmMqq34.jhrkm.cn
http://NB03eQU6.jhrkm.cn
http://n28iiDL4.jhrkm.cn
http://RxlxsSB5.jhrkm.cn
http://bj13S1we.jhrkm.cn
http://ZU2lubOK.jhrkm.cn
http://VYWJHDFZ.jhrkm.cn
http://DPt2NcU9.jhrkm.cn
http://pHyMBB5W.jhrkm.cn
http://iTBmqJb3.jhrkm.cn
http://enUYDI9B.jhrkm.cn
http://Bl1NqALg.jhrkm.cn
http://kRIR3QJa.jhrkm.cn
http://SrZmzpmd.jhrkm.cn
http://PELjiwNv.jhrkm.cn
http://3vWfFft4.jhrkm.cn
http://MdDaebyg.jhrkm.cn
http://wqPO8Sut.jhrkm.cn
http://A4cPykgb.jhrkm.cn
http://3PS2vMB4.jhrkm.cn
http://csY0efvM.jhrkm.cn
http://GM9qzSqx.jhrkm.cn
http://Qo8n7TNY.jhrkm.cn
http://7FIU52gJ.jhrkm.cn
http://www.dtcms.com/a/387503.html

相关文章:

  • Chromium 138 编译指南 macOS篇:配置depot_tools(三)
  • qt QHXYModelMapper详解
  • 机器学习中的编码问题和标准化:类别编码、one-hot编码缺陷及改进
  • Qt QHorizontalStackedBarSeries详解
  • Python爬虫实战:研究Pandas,构建全运会数据采集和分析系统
  • 告别冗余 DOM:Vue Fragment 用法与性能优化解析
  • 快速排序:原理、实现与优化
  • JavaScript性能优化实战:深入剖析性能瓶颈与最佳实践
  • Lattice ECP5系列FPGA介绍
  • PySpark 窗口函数row_number、lag、lead的使用简述
  • 华为FreeBuds 7i不同设备要如何连接?
  • 使用LVS架设服务器集群系统实现负载均衡与高可用的知识点详解
  • 84-dify案例分享-使用Qwen-Image实现文生图、图生图
  • 留个档,Unity,Animation控制相机,出现抖动的问题记录
  • CentOS 8.5部署Zabbix6.0 server端
  • CentOS系统下安装Docker记录
  • CentOS 7 如何安装 EPEL 源?epel-release-latest-7.noarch.rpm 安装教程(附安装保存)
  • CentOS 7 源码版 PhpMyAdmin 安装指南(适配 Nginx+PHP-FPM 环境)
  • 在 WSL Ubuntu 上使用 Docker 搭建可被 Ansible 控制的受控节点环境
  • 数据赋能,安全护航——D-QS工程造价数字化平台的数据治理与行业应用
  • Matplotlib 可视化:从基础绘图到高级定制
  • 知识管理与高效学习技术
  • 【AI总结】万字长文预警!Spring Boot 4 全景深度解析:从虚拟线程到声明式 HTTP 客户端,再到云原生最佳实践
  • 小杰机器学习(eight)——tensorflow进行线性回归——算法实现、数据加载、模型定义、模型保存与加载、查看网络结构。
  • 什么是网络安全态势感知
  • O3.6opencv风格迁移和人脸识别
  • uniapp h5本地域名调试解决跨域
  • IvorySQL 与 deepin 完成兼容性认证,共创开源生态新篇章
  • vue和springboot和ngnix跨域问题
  • 云边云科技4G路由器:连锁门店智慧联网的可靠基石