redis的数据类型及java调用案例

Redis 的丰富数据类型是它能够适应多种场景的核心原因。下面我会结合 Java(Jedis 客户端)  的代码示例,为你展示每种类型的典型用法和应用场景。


1. 准备工作:Java 连接 Redis

xml

xml
 体验AI代码助手
 代码解读
复制代码
<!-- Maven 依赖 -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>4.3.0</version>
</dependency>

java

typescript
 体验AI代码助手
 代码解读
复制代码
import redis.clients.jedis.Jedis;

public class RedisDemo {
    public static void main(String[] args) {
        // 连接本地 Redis 服务
        Jedis jedis = new Jedis("localhost", 6379);
        // 如果有密码
        // jedis.auth("password");
        System.out.println("连接成功: " + jedis.ping()); // 返回 PONG
    }
}

2. 各数据类型 Java 使用案例

2.1 String(字符串)

场景:缓存、计数器、分布式锁、分布式 ID 生成。

java

ini
 体验AI代码助手
 代码解读
复制代码
// 缓存
jedis.set("user:1000:name", "张三");
String name = jedis.get("user:1000:name");

// 计数器:文章阅读量
jedis.incr("article:1001:views");
long views = Long.parseLong(jedis.get("article:1001:views"));

// 分布式锁(仅示例,实际需考虑释放原子性)
String lockKey = "lock:order:100";
String requestId = UUID.randomUUID().toString();
String result = jedis.set(lockKey, requestId, "NX", "EX", 10); // 10秒过期
if ("OK".equals(result)) {
    try {
        // 执行业务逻辑
    } finally {
        // 释放锁(使用 Lua 脚本保证原子性)
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        jedis.eval(script, 1, lockKey, requestId);
    }
}

2.2 Hash(哈希)

场景:对象存储、购物车、动态统计。

java

kotlin
 体验AI代码助手
 代码解读
复制代码
// 存储用户对象
jedis.hset("user:1000", "name", "张三");
jedis.hset("user:1000", "age", "25");
jedis.hset("user:1000", "email", "zhangsan@example.com");

// 批量获取
Map<String, String> user = jedis.hgetAll("user:1000");
System.out.println(user.get("name")); // 张三

// 购物车(用户 1000 的商品 2001 数量 +1)
jedis.hincrBy("cart:1000", "2001", 1);
Long quantity = Long.parseLong(jedis.hget("cart:1000", "2001"));

2.3 List(列表)

场景:消息队列、最新列表、栈/队列。

java

dart
 体验AI代码助手
 代码解读
复制代码
// 最新评论列表(左侧插入)
jedis.lpush("comments:article:1001", "评论1", "评论2", "评论3");
// 获取最新 5 条
List<String> latestComments = jedis.lrange("comments:article:1001", 0, 4);

// 简单消息队列(生产者)
jedis.lpush("queue:task", "task1", "task2");
// 消费者(阻塞式)
List<String> tasks = jedis.brpop(0, "queue:task"); // 0 表示永久阻塞
String task = tasks.get(1);

2.4 Set(集合)

场景:去重、标签系统、共同好友、抽奖。

java

javascript
 体验AI代码助手
 代码解读
复制代码
// 抽奖:将用户 ID 加入集合
jedis.sadd("lottery:20231001", "user1", "user2", "user3", "user1"); // 重复添加无效
// 随机抽取 1 名中奖者
String winner = jedis.srandmember("lottery:20231001");
// 或抽中后移除
String winner2 = jedis.spop("lottery:20231001");

// 共同好友
jedis.sadd("user:1000:friends", "1001", "1002", "1003");
jedis.sadd("user:1001:friends", "1000", "1002", "1004");
Set<String> commonFriends = jedis.sinter("user:1000:friends", "user:1001:friends");
// 输出 [1002]

2.5 Sorted Set(有序集合)

场景:排行榜、延迟队列、带权重的任务调度。

java

javascript
 体验AI代码助手
 代码解读
复制代码
// 游戏积分榜
jedis.zadd("game:rank", 100, "player1");
jedis.zadd("game:rank", 95, "player2");
jedis.zadd("game:rank", 110, "player3");

// 获取前三名(按分数降序)
Set<String> top3 = jedis.zrevrange("game:rank", 0, 2);
// 获取玩家 1 的排名(0 开始)
Long rank = jedis.zrevrank("game:rank", "player1");

// 延迟队列:将任务按执行时间戳作为分数存入
long executeTime = System.currentTimeMillis() + 60000; // 1分钟后
jedis.zadd("delay:queue", executeTime, "task:100");
// 定时任务获取到期任务
Set<String> tasks = jedis.zrangeByScore("delay:queue", 0, System.currentTimeMillis());
for (String task : tasks) {
    // 处理任务
    jedis.zrem("delay:queue", task); // 处理完移除
}

2.6 Bitmap(位图)

场景:用户签到、活跃用户统计、布隆过滤器。

java

java
 体验AI代码助手
 代码解读
复制代码
// 用户 1000 在 2023-10-01 签到(偏移量 0 表示第一天)
jedis.setbit("sign:1000:202310", 0, true);
// 检查是否签到
Boolean signed = jedis.getbit("sign:1000:202310", 0);
// 统计当月签到次数
Long count = jedis.bitcount("sign:1000:202310");

// 日活统计:用户 ID 作为偏移量(限制 ID 连续)
jedis.setbit("active:20231001", 1000, true);
jedis.setbit("active:20231001", 1001, true);
Long dau = jedis.bitcount("active:20231001");

2.7 HyperLogLog

场景:UV 统计(允许误差)。

java

arduino
 体验AI代码助手
 代码解读
复制代码
// 添加访问用户
jedis.pfadd("uv:article:1001", "user1", "user2", "user3", "user1"); // user1 重复只计一次
// 获取 UV
long uv = jedis.pfcount("uv:article:1001");
// 合并多个页面的 UV
jedis.pfmerge("uv:total", "uv:article:1001", "uv:article:1002");

2.8 Geo(地理空间)

场景:附近的人、位置服务、配送范围判断。

java

kotlin
 体验AI代码助手
 代码解读
复制代码
// 添加位置(经度,纬度,成员名)
jedis.geoadd("locations", 116.404, 39.915, "北京");
jedis.geoadd("locations", 121.480, 31.235, "上海");
jedis.geoadd("locations", 113.264, 23.129, "广州");

// 计算北京到上海的距离(单位:km)
Double dist = jedis.geodist("locations", "北京", "上海", GeoUnit.KM);
System.out.println(dist); // 约 1067 km

// 查找半径 1000km 内的城市
List<GeoRadiusResponse> cities = jedis.georadiusByMember("locations", "北京", 1000, GeoUnit.KM);
for (GeoRadiusResponse city : cities) {
    System.out.println(city.getMemberByString()); // 北京、上海
}

2.9 Stream(流)

场景:可靠消息队列、事件溯源、日志管道。

java

javascript
 体验AI代码助手
 代码解读
复制代码
// 添加消息(每个消息有唯一 ID)
Map<String, String> msg = new HashMap<>();
msg.put("orderId", "1001");
msg.put("amount", "199");
String messageId = jedis.xadd("orders", StreamEntryID.NEW_ENTRY, msg, 10000, false);
System.out.println("Message ID: " + messageId);

// 消费者读取最新消息(阻塞)
List<Map.Entry<String, List<StreamEntry>>> entries = jedis.xread(1, 0, "orders");
for (Map.Entry<String, List<StreamEntry>> entry : entries) {
    for (StreamEntry se : entry.getValue()) {
        System.out.println(se.getFields()); // {orderId=1001, amount=199}
    }
}

// 消费者组(需 Redis 5.0+,Jedis 支持)
jedis.xgroupCreate("orders", "group1", new StreamEntryID("0"), true);
// 消费者读取并确认
List<Map.Entry<String, List<StreamEntry>>> groupEntries = jedis.xreadGroup("group1", "consumer1", 1, 0, false, "orders");
for (Map.Entry<String, List<StreamEntry>> entry : groupEntries) {
    for (StreamEntry se : entry.getValue()) {
        // 处理消息
        jedis.xack("orders", "group1", se.getID());
    }
}

3. 综合案例:用户会话管理与商品浏览历史

结合多种类型实现一个小功能: https://www.gaoding.com/templates/关于北京159.1415.8529北京开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于天津159.1415.8529天津开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于上海159.1415.8529上海开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于重庆159.1415.8529重庆开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于太原159.1415.8529太原开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于石家庄159.1415.8529石家庄开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于呼和浩特159.1415.8529呼和浩特开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于沈阳159.1415.8529沈阳开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于吉林159.1415.8529吉林开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于长春159.1415.8529长春开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于哈尔滨159.1415.8529哈尔滨开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于南京159.1415.8529南京开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于苏州159.1415.8529苏州开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于杭州159.1415.8529杭州开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于合肥159.1415.8529合肥开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于厦门159.1415.8529厦门开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于福州159.1415.8529福州开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于南昌159.1415.8529南昌开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于济南159.1415.8529济南开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于青岛159.1415.8529青岛开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于郑州159.1415.8529郑州开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于武汉159.1415.8529武汉开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于长沙159.1415.8529长沙开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于深圳159.1415.8529深圳开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于广州159.1415.8529广州开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于东莞159.1415.8529东莞开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于南宁159.1415.8529南宁开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于海口159.1415.8529海口开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于三亚159.1415.8529三亚开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于成都159.1415.8529成都开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于贵阳159.1415.8529贵阳开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于昆明159.1415.8529昆明开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于拉萨159.1415.8529拉萨开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于西安159.1415.8529西安开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于兰州159.1415.8529兰州开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于西宁159.1415.8529西宁开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于银川159.1415.8529银川开具仪器设备发票‖第一财经.html https://www.gaoding.com/templates/关于乌鲁木齐159.1415.8529乌鲁木齐开具仪器设备发票‖第一财经.html

java

javascript
 体验AI代码助手
 代码解读
复制代码
// 1. 用户登录:String 存 Token,Hash 存用户信息
String token = UUID.randomUUID().toString();
jedis.setex("token:" + token, 7200, "1000"); // 2小时过期
Map<String, String> userInfo = new HashMap<>();
userInfo.put("name", "张三");
userInfo.put("level", "vip");
jedis.hset("user:1000", userInfo);

// 2. 浏览商品:List 记录历史(保留最近 10 条)
String historyKey = "history:1000";
jedis.lpush(historyKey, "2001", "2002", "2003");
jedis.ltrim(historyKey, 0, 9); // 只保留 10 条
List<String> recent = jedis.lrange(historyKey, 0, 4); // 最近 5 条

// 3. 商品详情缓存:String 存 JSON
String productJson = "{"id":2001,"name":"手机","price":2999}";
jedis.setex("product:2001", 3600, productJson);

// 4. 排行榜:Sorted Set 记录热销商品
jedis.zincrby("hot:products", 1, "2001"); // 商品 2001 热度+1

// 5. 防重复下单:Set 记录已购买用户
if (!jedis.sismember("order:2001:buyers", "1000")) {
    // 执行下单逻辑
    jedis.sadd("order:2001:buyers", "1000");
}

4. 最佳实践提示

  • 连接池:生产环境使用 JedisPool 避免频繁创建连接。
  • 序列化:存储 Java 对象时建议用 JSON(Jackson)或 Protobuf,避免 JDK 原生序列化(体积大、不安全)。
  • 管道(Pipeline) :批量操作时用管道减少 RTT。
  • Lua 脚本:保证多个操作的原子性,如分布式锁释放。
  • 过期时间:缓存数据必须设置合理的 TTL,防止内存耗尽。
  • BigKey 规避:避免存储过大或元素过多的 key,使用 UNLINK 异步删除。
0
0
0
0
评论
未登录
暂无评论