一、前言:为什么选择 Jedis?
在 Java 生态中,操作 Redis 的主流客户端有:
- Jedis:轻量、简单、API 直接映射 Redis 命令
- Lettuce:基于 Netty,支持异步、响应式(Spring Boot 2.x+ 默认)
- Redisson:功能丰富,提供分布式锁、集合等高级特性
而 Jedis 凭借其极简 API、低学习成本、高性能 ,依然是许多项目的首选,尤其适合:
✅ 快速原型开发
✅ 对 Redis 命令熟悉、追求控制力的开发者
✅ 轻量级应用或微服务
本文将带你从零搭建 Jedis 环境,并实现常用数据类型操作。
二、环境准备
2.1 前提条件
- JDK 8+
- Maven 或 Gradle
- 本地或远程 Redis 服务(版本 ≥ 3.0)
bash
# 启动本地 Redis(Docker 示例)
docker run -d --name redis -p 6379:6379 redis:7.2
2.2 Maven 依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.1.2</version> <!-- 推荐使用最新稳定版 -->
</dependency>
💡 注意:Jedis 4.x+ 要求 Java 8+,5.x 支持 Redis 7+
三、Jedis 基础用法:单连接模式
⚠️ 仅用于测试!生产环境必须用连接池
java
import redis.clients.jedis.Jedis;
public class JedisDemo {
public static void main(String[] args) {
// 1. 创建 Jedis 实例(默认 localhost:6379)
try (Jedis jedis = new Jedis("localhost", 6379)) {
// 2. 测试连接
System.out.println("Redis 连接状态: " + jedis.ping()); // 返回 "PONG"
// 3. String 操作
jedis.set("name", "Alice");
System.out.println("name = " + jedis.get("name"));
// 4. 设置过期时间(秒)
jedis.setex("temp_key", 10, "临时数据");
// 5. Hash 操作
jedis.hset("user:1001", "age", "25");
jedis.hset("user:1001", "email", "alice@example.com");
System.out.println("用户邮箱: " + jedis.hget("user:1001", "email"));
// 6. List 操作
jedis.lpush("news", "头条", "科技", "体育");
System.out.println("最新新闻: " + jedis.lrange("news", 0, 1));
// 7. Set 操作
jedis.sadd("tags:1001", "java", "redis", "jedis");
System.out.println("是否包含 'redis': " + jedis.sismember("tags:1001", "redis"));
// 8. Sorted Set 操作
jedis.zadd("rank", 1500, "player1");
jedis.zadd("rank", 1800, "player2");
System.out.println("TOP1: " + jedis.zrevrange("rank", 0, 0));
}
}
}
✅ 输出示例:
Redis 连接状态: PONG
name = Alice
用户邮箱: alice@example.com
最新新闻: [体育, 科技]
是否包含 'redis': true
TOP1: [player2]
四、生产必备:Jedis 连接池(JedisPool)
单连接无法应对高并发,必须使用连接池!
4.1 配置连接池
java
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisPoolUtil {
private static JedisPool jedisPool;
static {
JedisPoolConfig config = new JedisPoolConfig();
// 最大连接数
config.setMaxTotal(20);
// 最大空闲连接
config.setMaxIdle(10);
// 获取连接时的最大等待时间(毫秒)
config.setMaxWaitMillis(2000);
// 在获取连接时检查有效性
config.setTestOnBorrow(true);
// 创建连接池(无密码)
jedisPool = new JedisPool(config, "localhost", 6379, 2000);
// 若有密码,使用:
// jedisPool = new JedisPool(config, "localhost", 6379, 2000, "your_password");
}
public static Jedis getJedis() {
return jedisPool.getResource();
}
public static void closePool() {
if (jedisPool != null) {
jedisPool.close();
}
}
}
4.2 使用连接池操作 Redis
java
public class UserService {
public void saveUser(String userId, String name, int age) {
try (Jedis jedis = JedisPoolUtil.getJedis()) {
jedis.hset("user:" + userId, "name", name);
jedis.hset("user:" + userId, "age", String.valueOf(age));
jedis.expire("user:" + userId, 3600); // 1小时过期
}
}
public Map<String, String> getUser(String userId) {
try (Jedis jedis = JedisPoolUtil.getJedis()) {
return jedis.hgetAll("user:" + userId);
}
}
}
✅ 优势:
- 复用连接,避免频繁创建/销毁
- 控制资源,防止连接耗尽
- 自动回收异常连接
五、常见数据类型操作封装示例
5.1 String 工具类
java
public class RedisStringUtil {
public static void set(String key, String value) {
try (Jedis jedis = JedisPoolUtil.getJedis()) {
jedis.set(key, value);
}
}
public static String get(String key) {
try (Jedis jedis = JedisPoolUtil.getJedis()) {
return jedis.get(key);
}
}
public static void setEx(String key, int seconds, String value) {
try (Jedis jedis = JedisPoolUtil.getJedis()) {
jedis.setex(key, seconds, value);
}
}
}
5.2 分布式锁(简易版)
java
public boolean tryLock(String lockKey, String requestId, int expireTime) {
try (Jedis jedis = JedisPoolUtil.getJedis()) {
// SET key value NX PX milliseconds
String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);
return "OK".equals(result);
}
}
public void unlock(String lockKey, String requestId) {
// 安全解锁需 Lua 脚本(略),此处简化
try (Jedis jedis = JedisPoolUtil.getJedis()) {
if (requestId.equals(jedis.get(lockKey))) {
jedis.del(lockKey);
}
}
}
⚠️ 注意:生产级分布式锁建议使用 Redisson
六、Jedis vs Lettuce:如何选择?
| 特性 | Jedis | Lettuce |
|---|---|---|
| 线程安全 | ❌ 单实例非线程安全(需连接池) | ✅ 线程安全 |
| 连接模型 | 阻塞 I/O | 基于 Netty 的异步非阻塞 |
| 内存占用 | 低 | 稍高 |
| Spring Boot 默认 | 1.x | 2.x+ |
| 学习曲线 | 极简 | 稍复杂 |
✅ 选型建议:
- 新项目 + Spring Boot 2+ → Lettuce
- 老项目 / 追求极致控制 / 轻量级 → Jedis
七、常见问题与最佳实践
❓ Q1:连接超时怎么办?
- 检查 Redis 是否启动
- 检查防火墙/安全组是否开放 6379
- 增加
JedisPoolConfig.setMaxWaitMillis
❓ Q2:中文乱码?
- Jedis 默认使用 UTF-8,确保你的字符串编码一致
- 避免直接存储二进制数据(可用 Base64 编码)
✅ 最佳实践
- 永远使用 try-with-resources 或手动 close()
- 生产环境必须用连接池
- key 命名规范 :如
user:{id}:profile - 设置 TTL,避免内存泄漏
- 监控连接池使用率 (
getActive()/getMaxTotal())
八、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!