Redis数据结构为字典Hash 实践 之 系统数据字典实时触发缓存存储

一.项目用redis-learn,文章参考

Hash底层存储数据的方式确实跟其他数据结构有点不同,其他数据结构几乎都是:Key-Value的存储,而Hash则是:Key – [Field-Value] 的存储,也就是说其他数据结构的Value一般是确切的值,而Hash的Value是一系列的键值对。

通常我们是这样称呼Hash的存储的:大Key为实际的Key,小Key为Field,而具体的取值为Field对应的值value
实践:系统数据字典实时触发缓存存储

二. 系统数据字典实时触发缓存存储

2.1 在数据库建立 系统字典 表 sys_dict_config

CREATE TABLE `sys_dict_config` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `type` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '字典类型',
  `name` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '字典名称',
  `code` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '选项编码',
  `value` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '选项取值',
  `order_by` int(11) DEFAULT '1' COMMENT '排序',
  `is_active` int(11) DEFAULT '1' COMMENT '是否有效(1=是;0=否)',
  `create_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`),
  KEY `idx_type_code` (`type`,`code`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2.2 新建实体类 SysDictConfig,SysDictConfigMapper,SysDictConfigMapper.xml,代码如下:
SysDictConfig:

package com.example.redislearn.entity;

import org.hibernate.validator.constraints.NotBlank;

import java.io.Serializable;
import java.util.Date;

public class SysDictConfig implements Serializable {
    private Integer id;

    @NotBlank(message = "字典类型不能为空")
    private String type;

    @NotBlank(message = "字典名称不能为空")
    private String name;

    @NotBlank(message = "选项编码不能为空")
    private String code;

    @NotBlank(message = "选项取值不能为空")
    private String value;

    //排序
    private Integer orderBy;

    //是否有效(1=是;0=否)
    private Byte isActive=1;

    //创建时间
    private Date createTime;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public Integer getOrderBy() {
        return orderBy;
    }

    public void setOrderBy(Integer orderBy) {
        this.orderBy = orderBy;
    }

    public Byte getIsActive() {
        return isActive;
    }

    public void setIsActive(Byte isActive) {
        this.isActive = isActive;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
}

SysDictConfigMapper:

package com.example.redislearn.dao;

import com.example.redislearn.entity.SysDictConfig;

import java.util.List;

public interface SysDictConfigMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(SysDictConfig sysDictConfig);

    int insertSelective(SysDictConfig sysDictConfig);

    SysDictConfig selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(SysDictConfig sysDictConfig);

    int updateByPrimaryKey(SysDictConfig sysDictConfig);

    List<SysDictConfig> selectActiveConfigs();
}

SysDictConfigMapper.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.redislearn.dao.SysDictConfigMapper" >

  <resultMap id="BaseResultMap" type="com.example.redislearn.entity.SysDictConfig" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="type" property="type" jdbcType="VARCHAR" />
    <result column="name" property="name" jdbcType="VARCHAR" />
    <result column="code" property="code" jdbcType="VARCHAR" />
    <result column="value" property="value" jdbcType="VARCHAR" />
    <result column="order_by" property="orderBy" jdbcType="INTEGER" />
    <result column="is_active" property="isActive" jdbcType="TINYINT" />
    <result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
  </resultMap>

  <sql id="Base_Column_List" >
    id, type, name, code, value, order_by, is_active, create_time
  </sql>

  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from sys_dict_config
    where id = #{id,jdbcType=INTEGER}
  </select>

  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
    delete from sys_dict_config
    where id = #{id,jdbcType=INTEGER}
  </delete>

  <insert id="insert" parameterType="com.example.redislearn.entity.SysDictConfig" >
    insert into sys_dict_config (id, type, name,
      code, value, order_by, 
      is_active, create_time)
    values (#{id,jdbcType=INTEGER}, #{type,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, 
      #{code,jdbcType=VARCHAR}, #{value,jdbcType=VARCHAR}, #{orderBy,jdbcType=INTEGER}, 
      #{isActive,jdbcType=TINYINT}, #{createTime,jdbcType=TIMESTAMP})
  </insert>

  <insert id="insertSelective" keyProperty="id" useGeneratedKeys="true" parameterType="com.example.redislearn.entity.SysDictConfig" >
    insert into sys_dict_config
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        id,
      </if>
      <if test="type != null" >
        type,
      </if>
      <if test="name != null" >
        name,
      </if>
      <if test="code != null" >
        code,
      </if>
      <if test="value != null" >
        value,
      </if>
      <if test="orderBy != null" >
        order_by,
      </if>
      <if test="isActive != null" >
        is_active,
      </if>
      <if test="createTime != null" >
        create_time,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #{id,jdbcType=INTEGER},
      </if>
      <if test="type != null" >
        #{type,jdbcType=VARCHAR},
      </if>
      <if test="name != null" >
        #{name,jdbcType=VARCHAR},
      </if>
      <if test="code != null" >
        #{code,jdbcType=VARCHAR},
      </if>
      <if test="value != null" >
        #{value,jdbcType=VARCHAR},
      </if>
      <if test="orderBy != null" >
        #{orderBy,jdbcType=INTEGER},
      </if>
      <if test="isActive != null" >
        #{isActive,jdbcType=TINYINT},
      </if>
      <if test="createTime != null" >
        #{createTime,jdbcType=TIMESTAMP},
      </if>
    </trim>
  </insert>

  <update id="updateByPrimaryKeySelective" parameterType="com.example.redislearn.entity.SysDictConfig" >
    update sys_dict_config
    <set >
      <if test="type != null" >
        type = #{type,jdbcType=VARCHAR},
      </if>
      <if test="name != null" >
        name = #{name,jdbcType=VARCHAR},
      </if>
      <if test="code != null" >
        code = #{code,jdbcType=VARCHAR},
      </if>
      <if test="value != null" >
        value = #{value,jdbcType=VARCHAR},
      </if>
      <if test="orderBy != null" >
        order_by = #{orderBy,jdbcType=INTEGER},
      </if>
      <if test="isActive != null" >
        is_active = #{isActive,jdbcType=TINYINT},
      </if>
      <if test="createTime != null" >
        create_time = #{createTime,jdbcType=TIMESTAMP},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>

  <update id="updateByPrimaryKey" parameterType="com.example.redislearn.entity.SysDictConfig" >
    update sys_dict_config
    set type = #{type,jdbcType=VARCHAR},
      name = #{name,jdbcType=VARCHAR},
      code = #{code,jdbcType=VARCHAR},
      value = #{value,jdbcType=VARCHAR},
      order_by = #{orderBy,jdbcType=INTEGER},
      is_active = #{isActive,jdbcType=TINYINT},
      create_time = #{createTime,jdbcType=TIMESTAMP}
    where id = #{id,jdbcType=INTEGER}
  </update>


  <select id="selectActiveConfigs" resultType="com.example.redislearn.entity.SysDictConfig">
    SELECT <include refid="Base_Column_List"/>
    FROM sys_dict_config
    WHERE is_active = 1
    ORDER BY type, order_by ASC
  </select>


</mapper>

2.3 RedisHashController类 ,代码如下:

package com.example.redislearn.controller;

import com.example.redislearn.entity.SysDictConfig;
import com.example.redislearn.response.BaseResponse;
import com.example.redislearn.response.StatusCode;
import com.example.redislearn.service.RedisHashService;
import com.example.redislearn.util.ValidatorUtil;
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Map;

/**
 * 数据类型Hash字典
 * Hash底层存储数据的方式确实跟其他数据结构有点不同,其他数据结构几乎都是:Key-Value的存储,
 * 而Hash则是:Key – [Field-Value] 的存储,也就是说其他数据结构的Value一般是确切的值,而Hash的Value是一系列的键值对,
 * 通常我们是这样称呼Hash的存储的:大Key为实际的Key,小Key为Field,而具体的取值为Field对应的值value。
 * 实践:系统数据字典实时触发缓存存储
 */

/**
 * 常用的方法:
 * 1. put(H key, HK hashKey, HV value);   新增hashMap值。
 * 2. putAll(H key, Map<? extends HK,? extends HV> m);以map集合的形式添加键值对。
 * 3. entries(H key); 获取key的列表元素。
 * 4. get(H key, Object hashKey); 获取变key中的指定field键是否有值,如果存在返回value,没有则返回null。
 * 5. keys(H key); 获取key中的所有field列表。
 * 6. hasKey(H key, Object hashKey);判断key是否有指定的field。
 * 7. delete(H key, Object... hashKeys); 删除key中的field-value对,可以传入多个参数,删除多个field-value对。
 * 8. size(H key);获取key的长度。
 */
@RestController
@RequestMapping("RedisHashController")
public class RedisHashController {

    private static final Logger log = LoggerFactory.getLogger(RedisHashController.class);

    @Autowired
    private RedisHashService redisHashService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    @RequestMapping(value = "/hashSet", method = RequestMethod.POST)
    public void hashSet() {
        log.info("----开始哈希Hash测试");
        final String key = "SpringBootRedis:Hash:Key:英雄联盟";
        redisTemplate.delete(key);

        HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
        hashOperations.put(key, "德玛西亚", "盖伦");
        hashOperations.put(key, "诺克萨斯", "德莱厄斯");

        Map<String, String> dataMap = Maps.newHashMap();
        dataMap.put("祖安", "蒙多");
        dataMap.put("艾欧尼亚", "艾瑞莉娅");
        hashOperations.putAll(key, dataMap);

        log.info("---哈希hash-获取列表元素: {} ", hashOperations.entries(key));
        log.info("---哈希hash-获取诺克萨斯的元素: {} ", hashOperations.get(key, "诺克萨斯"));
        log.info("---哈希hash-获取所有元素的field列表: {} ", hashOperations.keys(key));

        log.info("---哈希hash-祖安成员是否存在: {} ", hashOperations.hasKey(key, "祖安"));
        log.info("---哈希hash-艾欧尼亚成员是否存在: {} ", hashOperations.hasKey(key, "艾欧尼亚"));

        hashOperations.putIfAbsent(key, "暗影", "卡尔萨斯");
        log.info("---哈希hash-获取列表元素: {} ", hashOperations.entries(key));

        log.info("---哈希hash-删除元素德玛西亚、 诺克萨斯: {} ", hashOperations.delete(key, "德玛西亚", "诺克萨斯"));
        log.info("---哈希hash-获取列表元素: {} ", hashOperations.entries(key));

        log.info("---哈希hash-获取列表元素个数: {} ", hashOperations.size(key));
    }


    //==============================================系统数据字典实时触发缓存存储=================================================//


    /**
     * 添加数据字典及其对应的选项(field-value)
     * @param config
     * @param result
     * @return
     */
    @RequestMapping(value = "/addSysDictConfig",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public BaseResponse addSysDictConfig(@RequestBody @Validated SysDictConfig config, BindingResult result){
        String checkRes= ValidatorUtil.checkResult(result);
        /*if (StringUtils.isNotBlank(checkRes)){
            return new BaseResponse(StatusCode.Fail.getCode(),checkRes);
        }*/
        BaseResponse response=new BaseResponse(StatusCode.Success);
        try {
            redisHashService.addSysDictConfig(config);
        }catch (Exception e){
            response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
        }
        return response;
    }


    /**
     *获取缓存中所有的数据字典
     * @return
     */
    @RequestMapping(value = "getSysDictConfig",method = RequestMethod.GET)
    public BaseResponse getSysDictConfig(){
        BaseResponse response=new BaseResponse(StatusCode.Success);
        try {
            response.setData(redisHashService.getSysDictConfig());
        }catch (Exception e){
            response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
        }
        return response;
    }


    /**
     * 获取缓存中某个特定编码下数据字典的取值列表
     * @param type
     * @return
     */
    @RequestMapping(value = "get/type",method = RequestMethod.GET)
    public BaseResponse getType(@RequestParam String type){
        BaseResponse response=new BaseResponse(StatusCode.Success);
        try {
            response.setData(redisHashService.getByType(type));
        }catch (Exception e){
            response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
        }
        return response;
    }

}

2.4 业务类:RedisHashService,代码如下:

package com.example.redislearn.service;

import com.example.redislearn.dao.SysDictConfigMapper;
import com.example.redislearn.entity.SysDictConfig;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;

@Service
public class RedisHashService {

    private static final Logger log = LoggerFactory.getLogger(RedisHashService.class);

    private static final String RedisHashKey = "Redis:Hash";

    @Autowired
    private SysDictConfigMapper sysDictConfigMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    /**
     * 添加数据字典及其对应的选项(code-value)
     *
     * @param config
     * @return
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    public Integer addSysDictConfig(SysDictConfig config) throws Exception {
        int res = sysDictConfigMapper.insertSelective(config);
        if (res > 0) {
            //实时触发数据字典的hash存储
            cacheConfigMap();
        }
        return config.getId();
    }


    /**
     * 取出缓存中所有的数据字典列表
     */
    public Map<String, List<SysDictConfig>> getSysDictConfig() throws Exception {
        return getAllCacheConfig();
    }


    /**
     * 取出缓存中特定的数据字典列表
     *
     * @param type
     * @return
     * @throws Exception
     */
    public List<SysDictConfig> getByType(final String type) throws Exception {
        return getCacheConfigByType(type);
    }


    /**
     * 实时获取所有有效的数据字典列表-转化为map-存入hash缓存中
     */
    @Async
    public void cacheConfigMap() {
        try {
            List<SysDictConfig> sysDictConfigList = sysDictConfigMapper.selectActiveConfigs();
            if (sysDictConfigList != null && !sysDictConfigList.isEmpty()) {
                Map<String, List<SysDictConfig>> dataMap = Maps.newHashMap();
                //所有的数据字典列表遍历 -> 转化为 hash存储的map
                sysDictConfigList.forEach(sysDictConfig -> {
                    List<SysDictConfig> list = dataMap.get(sysDictConfig.getType());
                    if (CollectionUtils.isEmpty(list)) {
                        list = Lists.newLinkedList();
                    }
                    list.add(sysDictConfig);
                    dataMap.put(sysDictConfig.getType(), list);
                });

                //存储到缓存hash中
                HashOperations<String, String, List<SysDictConfig>> hashOperations = redisTemplate.opsForHash();
                hashOperations.putAll(RedisHashKey, dataMap);
            }
        } catch (Exception e) {
            log.error("实时获取所有有效的数据字典列表-转化为map-存入hash缓存中-发生异常:", e.fillInStackTrace());
        }
    }


    /**
     * 从缓存hash中获取所有的数据字典配置map
     *
     * @return
     */
    public Map<String, List<SysDictConfig>> getAllCacheConfig() {
        Map<String, List<SysDictConfig>> map = Maps.newHashMap();
        try {
            HashOperations<String, String, List<SysDictConfig>> hashOperations = redisTemplate.opsForHash();
            map = hashOperations.entries(RedisHashKey);
        } catch (Exception e) {
            log.error("从缓存hash中获取所有的数据字典配置map-发生异常:", e.fillInStackTrace());
        }
        return map;
    }


    /**
     * 从缓存hash中获取特定的数据字典列表
     *
     * @param type
     * @return
     */
    public List<SysDictConfig> getCacheConfigByType(final String type) {
        List<SysDictConfig> list = Lists.newArrayList();
        try {
            HashOperations<String, String, List<SysDictConfig>> hashOperations = redisTemplate.opsForHash();
            list = hashOperations.get(RedisHashKey, type);
        } catch (Exception e) {
            log.error("从缓存hash中获取特定的数据字典列表-发生异常:", e.fillInStackTrace());
        }
        return list;
    }

}

三.测试

启动项目
测试 添加数据字典及其对应的选项(field-value)
在浏览器或postman 上输入:http://127.0.0.1:8782/RedisHashController/addSysDictConfig
post请求
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
测试 获取缓存中所有的数据字典 功能:
在浏览器或postman 上输入:http://127.0.0.1:8782/RedisHashController/getSysDictConfig
get请求
在这里插入图片描述
测试 获取缓存中某个特定编码下数据字典的取值列表 功能:
在浏览器或postman 上输入:http://127.0.0.1:8782/RedisHashController/get/type?type=sex
get请求
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Redis是一款开源的内存数据库,可以用于缓存各种类型的数据,包括字典数据。使用Redis缓存字典数据有以下几个好处: 首先,Redis的内存读写速度非常快,相较于传统的数据库,访问Redis的速度更快。这使得使用Redis缓存字典数据可以显著提高应用程序的性能和响应速度。 其次,Redis支持持久化功能,可以将缓存字典数据保存到硬盘上。这样即使服务器重启或者发生故障,也不会丢失缓存数据,可以保证数据的可靠性和持久性。 再次,Redis提供了一些高级数据结构和功能,如SortedSet和Hash。这些数据结构可以非常方便地用于存储和查询字典数据。例如,可以使用Hash数据结构字典数据按照字段存储,可以直接通过字段名进行快速的数据查询和更新操作。 此外,Redis具有良好的扩展性。可以通过集群方式部署多个Redis服务器,实现高可用性和负载均衡。这样即使有大量的字典数据需要缓存,也可以通过横向扩展的方式满足需求,保证系统的可伸缩性和稳定性。 最后,Redis还提供了丰富的命令和API,可以方便地操作缓存字典数据。可以通过设置过期时间、设置缓存策略等来控制缓存的生命周期和数据的更新机制,灵活地应对不同的业务需求。 综上所述,使用Redis缓存字典数据可以提升应用程序的性能和响应速度,确保数据的可靠性和持久性,提供方便的操作和扩展方式,满足不同的业务需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘德华一不小心就打代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值