一、Redis Java客户端选型
1.1 主流Java客户端对比
客户端 | 特点 | 适用场景 | 性能基准 |
---|---|---|---|
Jedis | 同步阻塞IO,线程不安全 | 简单应用,连接池管理 | 50,000 ops/s |
Lettuce | 异步非阻塞IO,Netty实现 | 高并发,响应式编程 | 80,000 ops/s |
Redisson | 分布式服务封装,丰富功能 | 分布式系统集成 | 60,000 ops/s |
1.2 Jedis基本使用
// 创建连接池配置
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(128);
poolConfig.setMaxIdle(32);
poolConfig.setMinIdle(8);
// 创建连接池
try (JedisPool jedisPool = new JedisPool(poolConfig, "localhost", 6379);
Jedis jedis = jedisPool.getResource()) {
// 字符串操作
jedis.set("user:1001", "张三");
String userName = jedis.get("user:1001");
// 哈希操作
jedis.hset("user:1001:info", "age", "28");
Map<String, String> userInfo = jedis.hgetAll("user:1001:info");
}
二、Redis数据结构Java实现
2.1 字符串操作优化
// 批量操作减少网络开销
List<String> keys = Arrays.asList("key1", "key2", "key3");
List<String> values = jedis.mget(keys.toArray(new String[0]));
// 原子计数器
jedis.incr("article:1001:views");
jedis.incrBy("user:1001:credits", 10);
2.2 哈希结构应用
// 存储对象
public void saveUser(User user) {
Map<String, String> hash = new HashMap<>();
hash.put("id", user.getId());
hash.put("name", user.getName());
hash.put("age", String.valueOf(user.getAge()));
jedis.hmset("user:" + user.getId(), hash);
}
// 获取对象
public User getUser(String userId) {
Map<String, String> hash = jedis.hgetAll("user:" + userId);
User user = new User();
user.setId(hash.get("id"));
user.setName(hash.get("name"));
user.setAge(Integer.parseInt(hash.get("age")));
return user;
}
三、Java中的Redis高级特性
3.1 管道技术实现
// Jedis管道示例
Pipeline pipeline = jedis.pipelined();
pipeline.set("key1", "value1");
pipeline.incr("counter");
pipeline.zadd("sortedSet", 1, "member");
List<Object> results = pipeline.syncAndReturnAll();
// Lettuce异步管道
StatefulRedisConnection<String, String> connection = client.connect();
RedisAsyncCommands<String, String> async = connection.async();
async.setAutoFlushCommands(false);
async.set("key1", "value1");
async.incr("counter");
async.zadd("sortedSet", 1, "member");
async.flushCommands();
3.2 发布订阅模式
// Jedis订阅实现
new Thread(() -> {
jedis.subscribe(new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
System.out.println("收到消息: " + message);
}
}, "channel1");
}).start();
// 发布消息
jedis.publish("channel1", "Hello Redis!");
四、Spring整合Redis
4.1 Spring Data Redis配置
@Configuration
public class RedisConfig {
@Bean
public RedisConnectionFactory redisConnectionFactory() {
LettuceConnectionFactory factory = new LettuceConnectionFactory();
factory.setHostName("localhost");
factory.setPort(6379);
factory.setDatabase(0);
return factory;
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory());
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
}
4.2 Repository模式使用
@RedisHash("persons")
public class Person {
@Id String id;
String name;
Integer age;
// getters/setters
}
public interface PersonRepository extends CrudRepository<Person, String> {
List<Person> findByName(String name);
}
// 使用示例
personRepository.save(new Person("1001", "张三", 28));
Person person = personRepository.findById("1001").get();
五、Redis缓存实战
5.1 Spring Cache集成
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
.disableCachingNullValues();
return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.transactionAware()
.build();
}
}
@Service
public class UserService {
@Cacheable(value = "users", key = "#userId")
public User getUser(String userId) {
// 数据库查询逻辑
}
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
// 更新数据库
return user;
}
@CacheEvict(value = "users", key = "#userId")
public void deleteUser(String userId) {
// 删除数据库记录
}
}
5.2 缓存穿透解决方案
// 布隆过滤器实现
public class BloomFilter {
private final Jedis jedis;
private final String filterName;
public BloomFilter(Jedis jedis, String filterName) {
this.jedis = jedis;
this.filterName = filterName;
}
public void add(String value) {
jedis.setbit(filterName, hash(value), true);
}
public boolean exists(String value) {
return jedis.getbit(filterName, hash(value));
}
private long hash(String value) {
// 简单哈希实现,实际应使用多个哈希函数
return Math.abs(value.hashCode()) % (1 << 32);
}
}
// 使用示例
BloomFilter filter = new BloomFilter(jedis, "user_filter");
if (!filter.exists(userId)) {
return null; // 不存在直接返回
}
六、Redis事务与Lua脚本
6.1 Java中的Redis事务
// Jedis事务示例
Transaction tx = jedis.multi();
try {
tx.set("key1", "value1");
tx.incr("counter");
tx.exec();
} catch (Exception e) {
tx.discard();
}
// Spring事务集成
@Transactional
public void transfer(String from, String to, int amount) {
redisTemplate.opsForValue().decrement(from, amount);
redisTemplate.opsForValue().increment(to, amount);
}
6.2 Lua脚本执行
// 执行Lua脚本
String script = "local current = redis.call('GET', KEYS[1])\n" +
"if current and tonumber(current) >= tonumber(ARGV[1]) then\n" +
" return redis.call('DECRBY', KEYS[1], ARGV[1])\n" +
"else\n" +
" return -1\n" +
"end";
List<String> keys = Collections.singletonList("inventory:1001");
List<String> args = Collections.singletonList("5");
Long result = (Long) jedis.eval(script, keys, args);
七、Redis集群与哨兵模式
7.1 集群模式配置
// Jedis集群配置
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("127.0.0.1", 7001));
nodes.add(new HostAndPort("127.0.0.1", 7002));
nodes.add(new HostAndPort("127.0.0.1", 7003));
JedisCluster cluster = new JedisCluster(nodes, 2000, 5);
cluster.set("clusterKey", "value");
String value = cluster.get("clusterKey");
7.2 哨兵模式配置
// Lettuce哨兵配置
RedisURI redisUri = RedisURI.Builder.sentinel("sentinel1", 26379)
.withSentinel("sentinel2", 26379)
.withSentinel("sentinel3", 26379)
.withMasterId("mymaster")
.build();
RedisClient client = RedisClient.create(redisUri);
StatefulRedisConnection<String, String> connection = client.connect();
八、性能监控与调优
8.1 Jedis连接池监控
// 连接池监控指标
GenericObjectPoolConfig<Jedis> config = new GenericObjectPoolConfig<>();
config.setJmxEnabled(true);
config.setJmxNamePrefix("redis-pool");
config.setJmxNameBase("type=RedisPool");
// 获取监控数据
int active = jedisPool.getNumActive();
int idle = jedisPool.getNumIdle();
int waiters = jedisPool.getNumWaiters();
8.2 慢查询分析
// 获取慢查询日志
List<Slowlog> slowlogs = jedis.slowlogGet();
for (Slowlog log : slowlogs) {
System.out.println("命令: " + log.getArgs() +
" 执行时间: " + log.getExecutionTime() + "微秒");
}
// 重置慢查询日志
jedis.slowlogReset();
九、安全最佳实践
9.1 SSL连接配置
// Lettuce SSL配置
RedisURI redisUri = RedisURI.create("rediss://localhost");
redisUri.setVerifyPeer(false); // 生产环境应验证证书
RedisClient client = RedisClient.create(redisUri);
StatefulRedisConnection<String, String> connection = client.connect();
9.2 访问控制
// 认证配置
JedisPoolConfig poolConfig = new JedisPoolConfig();
JedisPool jedisPool = new JedisPool(poolConfig, "localhost", 6379, 2000, "password");
// ACL用户管理(Redis 6.0+)
jedis.aclSetUser("appuser", "on", ">apppassword",
"+@read", "+@write", "-@admin");
十、实战案例:秒杀系统设计
@Service
public class SeckillService {
private final RedisTemplate<String, Object> redisTemplate;
public SeckillService(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public boolean seckill(String productId, String userId) {
// 1. 校验库存
Integer stock = (Integer) redisTemplate.opsForValue().get("stock:" + productId);
if (stock == null || stock <= 0) {
return false;
}
// 2. 使用Lua脚本保证原子性
String script = "local stock = tonumber(redis.call('GET', KEYS[1]))\n" +
"if stock > 0 then\n" +
" redis.call('DECR', KEYS[1])\n" +
" redis.call('SADD', KEYS[2], ARGV[1])\n" +
" return 1\n" +
"else\n" +
" return 0\n" +
"end";
List<String> keys = Arrays.asList("stock:" + productId, "success:" + productId);
Long result = (Long) redisTemplate.execute(
new DefaultRedisScript<>(script, Long.class),
keys, userId);
return result == 1;
}
}
结语
通过本文的Java视角Redis实践指南,我们深入探讨了Redis在Java生态系统中的各种应用场景和最佳实践。从基础数据结构操作到高级特性应用,从单机部署到集群管理,这些知识将帮助您构建高性能、可靠的Java应用系统。