【问题标题】:Get complete Map from Redis if a key contains a String如果键包含字符串,则从 Redis 获取完整的 Map
【发布时间】:2020-09-21 10:19:31
【问题描述】:

我能够从 Redis 添加和获取特定的用户对象 我正在添加这样的对象:

 private static final String USER_PREFIX = ":USER:";
 public void addUserToRedis(String serverName,User user) {
    redisTemplate.opsForHash().put(serverName + USER_PREFIX + user.getId(),  
   Integer.toString(user.getId()),user);    
    }

如果 userId 为 100,我可以通过密钥获取:SERVER1:USER:100
现在我想以 Map<String,List<User>> 检索所有用户,
比如通过这个键获取所有用户SERVER1:USER:
可以吗?或者我需要修改我的 addUserToRedis 方法?请给我建议。

【问题讨论】:

  • 您可以进行通配符搜索。 “服务器:用户:*”。检查 redis 中的模式搜索
  • 它适用于通配符搜索。

标签: redis spring-data-redis


【解决方案1】:

我建议不要在生产中使用“KEYS”命令,因为这会严重影响 REDIS 延迟 (can even bring down the cluster if you have a large number of keys stored)
相反,您可能希望使用与普通 GET/SET 不同的命令。

如果您使用SetsHashes 会更好

127.0.0.1:6379> sadd server1 user1 user2
(integer) 2
127.0.0.1:6379> smembers server1
1) "user2"
2) "user1"
127.0.0.1:6379>

使用集合,您可以简单地将用户添加到服务器密钥并获取服务器上的整个用户列表。

如果您确实需要< server, list < users > > 的映射,您可以使用带有字符串化用户数据的哈希,然后在应用层将其转换为实际的User POJO

127.0.0.1:6379> hset server2 user11 name
(integer) 1
127.0.0.1:6379> hset server2 user13 name
(integer) 1
127.0.0.1:6379> hgetall server2
1) "user11"
2) "name"
3) "user13"
4) "name"
127.0.0.1:6379>

另外请注意,将这么多大数据保存在一个键中并不是一个理想的做法。

【讨论】:

    【解决方案2】:

    我不使用 java 但这里是如何使用 SCAN

    const Redis = require('ioredis')
    const redis = new Redis()
    
    async function main() {
        const stream = redis.scanStream({
            match: "*:user:*",
            count: 100,
        })
    
        stream.on("data", (resultKeys) => {
            for (let i = 0; i < resultKeys.length; i++) {
                // console.log(resultKeys[i])
                // do your things here
            }
        });
        stream.on("end", () => {
            console.log("all keys have been visited");
        });
    }
    
    main()
    

    【讨论】:

      【解决方案3】:

      最后我想出了通配符搜索和避免KEYS的解决方案,这是我的完整方法:

        public Map<String, User> getUserMapFromRedis(String serverName){
          Map<String, User> users=new HashMap<>();
           RedisConnection redisConnection = null;
           try {
                  redisConnection = redisTemplate.getConnectionFactory().getConnection();
                 ScanOptions options = ScanOptions.scanOptions().match(serverName + USER_PREFIX+"*").build();
                 Cursor<byte[]> scan = redisConnection.scan(options);
                 while (scan.hasNext()) {
                 byte[] next = scan.next();
                 String key = new String(next, StandardCharsets.UTF_8);
                 String[] keyArray=key.split(":");
                 String userId=keyArray[2];
                 User user=//get User by userId From Redis
                 users.put(userId, user);
                 }
                 try {
                 scan.close();
            } catch (IOException e) {
                
            }
             }finally {
             redisConnection.close(); //Ensure closing this connection.
             }
           return users;
          }
      

      【讨论】:

      • KEYS 会阻塞 redis 服务器。如果必须,您可以尝试使用 SCAN
      • @TuanAnhTran 能否指导我在这种情况下如何使用 redisTemplate,这将非常有帮助
      • 我不使用 java 但这里是如何使用 nodejs stackoverflow.com/a/64007618/2688699
      • @TuanAnhTran 我编辑了我的答案以避免使用 KEYS,现在我正在使用 SCAN。这个好吗?
      • 是的,应该没问题。您可以通过创建数百万个密钥进行测试并亲自查看:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-27
      • 2020-03-24
      • 1970-01-01
      • 2017-10-19
      • 1970-01-01
      • 2019-01-14
      相关资源
      最近更新 更多