当前位置:   article > 正文

Redis的数据类型Hash使用场景实战_redis opsforhash

redis opsforhash

Redis的数据类型Hash使用场景

常见面试题:redis在你们项目中是怎么用的,除了String数据类型还使用什么数据类型?
怎么保证缓存和数据一致性等问题…

Hash模型使用场景

知识回顾:

redisTemplate.opsForHash() 方法是 Redis 的 Hash(哈希)数据结构的操作模板方法。它返回一个 HashOperations 实例,可以使用该实例执行对哈希数据结构的各种操作,如添加、删除、获取元素、获取全部元素等。

使用 redisTemplate.opsForHash() 方法进行哈希操作的示例如下:

// 添加元素到哈希
redisTemplate.opsForHash().put("myhash", "key1", "value1");
redisTemplate.opsForHash().put("myhash", "key2", "value2");

// 获取哈希中指定的元素
String value1 = (String) redisTemplate.opsForHash().get("myhash", "key1");

// 获取哈希中所有元素
Map<Object, Object> allEntries = redisTemplate.opsForHash().entries("myhash");

// 删除哈希中指定的元素
redisTemplate.opsForHash().delete("myhash", "key1");

// 判断哈希中是否存在指定的元素
boolean exist = redisTemplate.opsForHash().hasKey("myhash", "key1");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

场景使用场景

1,对象缓存 比如存储用户信息 一个字段对应多个属性
id:1 、name:老许 、 age:18 、 sex:0 、 hobby:java …

2、同一个用户在不同所属系统的待办个数统计
在这里插入图片描述

代码实现

应用场景一:保存用户的信息 h:user_key_prefix + account hk:acount hv:user

引入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
  • 1
  • 2
  • 3
  • 4

项目启动时候自动将数据库用户信息保存到redis中

package com.xx.xx.xx.config;

import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author psd
 */
@Slf4j
@Configuration
public class SysUserConfig {

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedisOperationUtils redisOperationUtils;


    @PostConstruct
    public void init() {
        // 查询所有的用户信息
        List<SysUserEntity> userEntityList = sysUserService.queryAllSysUser();
        List<String> accountList = userEntityList.stream().map(SysUserEntity::getAccount).collect(Collectors.toList());
        // 清除缓存中的数据 
        accountList.stream().forEach(account -> redisTemplate.delete(redisOperationUtils.USER_KEY_PREFIX + account));
        // 重新新增缓存中的数据
        userEntityList.stream().forEach(userEntity -> {
            // 设置一个随机过期时间 4 ~ 8小时
            redisTemplate.opsForHash().put(redisOperationUtils.USER_KEY_PREFIX + userEntity.getAccount(), userEntity.getAccount(),
                    JSON.toJSONString(userEntity));
            redisTemplate.expire(redisOperationUtils.USER_KEY_PREFIX + userEntity.getAccount(), 3600 + redisOperationUtils.random.nextInt(4 * 3600),
                    TimeUnit.SECONDS);
        });
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

配置类


@Component
public class RedisOperationUtils {
    /**
     * 用户信息redis中的key
     */
    public final String USER_KEY_PREFIX = "rbac:user:";

    public final Random random = new SecureRandom();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

项目中任意获取的可以

 @Test
    public void test03(){
        Object o = redisTemplate.opsForHash().get(redisOperationUtils.USER_KEY_PREFIX + "Lin" , "Lin");
        SysUserEntity entity = JSON.parseObject((String) o, SysUserEntity.class);
        System.out.println("entity = " + entity);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可能存在疑问点:
1、为啥没有用String类型 同样可以满足,这个是考虑到有些字段可能会改动,项目在初期阶段可能某些字段会修改,添加新增,包括删除, 总和优先考虑Hash模型,利于维护,不用单个字段进行修改 删除等操作

2、如果数据有修改的情况下,你是怎么保证数据类型一致性
先删除redis中的数据,再写数据到mysql 再删除redis中数据

优点细节有以下几处:
1、设置过期时间时候,没有采用 每次new Random();而是放到一个工具类里面,节约内存
2、使用Random random = new SecureRandom(); 是安全的,
3、采用随机过期时间,随机性比较好 减少redis的内存使用

应用场景二:保存用户的信息 h:phoneNum hk:typeStr hv:count
	//  h:phoneNum hk:typeStr hv:count  
	// 对应唯一标识手机号: 139xxxxxxxx hk:数据来源类型  hv:个数	
    @Override
    public void insertTask() {
        redisTemplate.opsForHash().put(redisOperationUtils.KEY_PREFIX + "18900001111", "xj", "10");
        redisTemplate.opsForHash().put(redisOperationUtils.KEY_PREFIX + "18900001111", "kd", "8");
        redisTemplate.opsForHash().put(redisOperationUtils.KEY_PREFIX + "18900001111", "yh", "6");

        redisTemplate.opsForHash().put(redisOperationUtils.KEY_PREFIX + "15665440000", "xj", "2");
        redisTemplate.opsForHash().put(redisOperationUtils.KEY_PREFIX + "15665440000", "kd", "3");
        redisTemplate.opsForHash().put(redisOperationUtils.KEY_PREFIX + "15665440000", "yh", "12");

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

再获取时候

// 获取的taskCountStr 注意是个字符串,需要做类型转换,封装成vo给前端,用于渲染 具体业务具体分析
 String taskCountStr = (String) redisTemplate.opsForHash().get(redisOperationUtils.KEY_PREFIX + "153xxxxxxxx", taskEnum.getOwningSystemCode());
  • 1
  • 2

喜欢我的文章的话,点个阅读或者点个点赞,是我编写博客的动力,持续更新中

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/秋刀鱼在做梦/article/detail/800905
推荐阅读
相关标签
  

闽ICP备14008679号