批量查询在线成员对应节点redis

java 复制代码
package com.kongjs.im.message.service;


import com.alibaba.fastjson2.JSON;
import com.kongjs.im.common.dto.UserDeviceOnlineDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;


import java.util.*;

@Slf4j
@Service
public class ImOnlineService {

    private static final String USER_ONLINE = "im:online:device:{%s}";

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 【同步非响应式】
     * 批量获取多个用户的 完整在线设备信息(Hash 全量数据)
     *
     * @param userIds 用户ID列表
     * @return Map<userId, Map<deviceId, UserDeviceOnlineDTO>>
     */
    public Map<Long, Map<String, UserDeviceOnlineDTO>> batchGetUserOnlineInfo(List<Long> userIds) {
        if (userIds == null || userIds.isEmpty()) {
            return Collections.emptyMap();
        }
        // 1. 构建批量 KEY
        List<String> keys = new ArrayList<>();
        for (Long userId : userIds) {
            keys.add(String.format(USER_ONLINE, userId));
        }
        // 2. Lua 脚本:批量 hgetall
        DefaultRedisScript<List<List<String>>> script = new DefaultRedisScript<>();
        script.setScriptText("""
                    local result = {}
                    for i = 1, #KEYS do
                        local data = redis.call('HGETALL', KEYS[i])
                        table.insert(result, data)
                    end
                    return result
                """);
        //script.setResultType(List.class);
        // 3. 执行 Lua(同步)
        List<List<String>> rawResult = stringRedisTemplate.execute(script, keys);
        // 4. 解析结果
        Map<Long, Map<String, UserDeviceOnlineDTO>> finalMap = new HashMap<>(rawResult.size());
        for (int i = 0; i < userIds.size(); i++) {
            Long userId = userIds.get(i);
            List<String> hashData = rawResult.get(i);
            Map<String, UserDeviceOnlineDTO> deviceMap = new HashMap<>();
            for (int j = 0; j < hashData.size(); j += 2) {
                String deviceId = hashData.get(j);
                String json = hashData.get(j + 1);
                // JSON 转你的 DTO
                UserDeviceOnlineDTO dto = null;
                try {
                    dto = JSON.parseObject(json, UserDeviceOnlineDTO.class);
                } catch (Exception e) {
                    log.error("{}", e.getMessage());
                }
                if (dto != null) {
                    deviceMap.put(deviceId, dto);
                }
            }
            finalMap.put(userId, deviceMap);
        }
        return finalMap;
    }
}
相关推荐
l1t16 分钟前
DeepSeek总结的有符号、无符号、未对齐:从汇编到 SQL 的教训
汇编·数据库·sql
麦壳饼32 分钟前
SonnetDB SQL Cookbook:常用查询模式速查
数据库·sonnetdb
Sand(ContextGate)1 小时前
从零搭建电商智能导购 Agent:LangGraph 编排 + 三层记忆 + 熔断降级 + 生产部署全链路实战
redis·agent·fastapi·电商·chromadb·langgraph·智能导购
for_ever_love__1 小时前
LangChain Text-to-SQL:让不会写 SQL 的人查数据库
数据库·sql·langchain·大模型·agent·rag·问答
梦想不只是梦与想1 小时前
SQLAlchemy:查询与操作 (三)
数据库·python·sqlalchemy
Aric_Jones2 小时前
WAL / CDC / 复制槽 /位点
数据库·oracle
草莓熊Lotso2 小时前
【C++ 基于微服务的即时通讯系统】基建三件套:gflags + gtest + spdlog 源码编译安装与实战入门
linux·网络·数据库·c++·微服务·log4j
bksczm2 小时前
Redis基础篇之初识分布式
数据库·redis·分布式
jyOverQ2 小时前
Redis 主从复制、Sentinel 和 Cluster 到底有什么区别?
java·redis·sentinel
for_ever_love__2 小时前
MySQL 索引类型全解:B+Tree / Hash / R-Tree / 全文 的底层差异,以及一次性建对的选型表
数据库·mysql·b+树·唯一索引·全文索引·索引类型·索引分类