springboot集成redis之字典缓存

news2024/11/13 10:49:23

什么是redis的字典缓存?

Redis的缓存是Redis内部用于存储键值对数据结构的一种基础数据结构。在Redis中,所有的键值对都是通过字典这种数据结构来存储的。字典在Redis中扮演着核心角色,因为它不仅用于数据库中的键值对存储,还用于实现其他如哈希、集合等复杂数据结构。
以下是关于Redis字典缓存的一些关键点:

  1. 数据结构:Redis的字典使用哈希表作为底层实现,这样可以提供快速的查找、添加和删除操作。哈希表通常是一个数组,数组的每个元素是一个指向键值对结构的指针。
  2. 哈希冲突解决:当不同的键通过哈希函数映射到同一个位置时,Redis使用链表法来解决冲突。如果一个位置有多个键值对,它们会形成一个链表。
  3. rehash:随着键值对数量的增加或减少,为了维持哈希表的性能,Redis会进行rehash操作,即重新计算所有键的哈希值,并将它们重新分布到新的哈希表中。
  4. 渐进式rehash:为了避免rehash操作带来的性能问题,Redis使用渐进式rehash。它将rehash操作分散到对字典的每个添加、删除、查找和更新操作中,从而避免了一次性rehash可能导致的长时间延迟。
  5. 缓存作用:由于字典的高效访问特性,Redis可以快速读写数据,这使得Redis非常适合作为缓存系统使用。在字典中存储的数据可以直接从内存中访问,大大减少了数据读取的时间。
  6. 持久化:虽然字典是内存中的数据结构,但Redis支持将字典中的数据持久化到硬盘上,以保证在系统故障时数据不会丢失。
  7. 类型特定字典:Redis支持多种数据类型,如字符串、列表、集合、哈希、有序集合等,每种数据类型在内部都可能使用到字典结构来存储元数据或数据本身。

Redis的字典缓存是支撑其高性能的一个关键因素,它使得Redis能够以极快的速度处理大量的数据。

项目目录

image.png

代码实践

entity层
package com.wyl.redis.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;

/**
 * @Description 
 * @Author wuyilong
 * @Date 2024-07-03
 */
@Data
@TableName("full_city")
@Entity
@Table(name="full_city")
public class FullCity extends Model<FullCity> {

    private static final long serialVersionUID = 1L;

    /**
     * 主键id
     */
    @TableId(value = "id", type = IdType.AUTO)
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    /**
     * 名称
     */
    @TableField("name")
    private String name;

    /**
     * 行政编码
     */
    @TableField("code")
    private String code;

    /**
     * 全名称
     */
    @TableField("full_name")
    private String fullName;

    /**
     * 级别,1省,2市,3区,4街道
     */
    @TableField("level")
    private Integer level;

    /**
     * 创建时间
     */
    @TableField("create_time")
    private Date createTime;

    /**
     * 中心点
     */
    @TableField("center")
    private String center;

    /**
     * 是否被撤销,0否,1是
     */
    @TableField("is_revoke")
    private Integer isRevoke;

    /**
     * 父级编码
     */
    private String parentCode;


    @Override
    public Serializable pkVal() {
        return this.id;
    }

}

service层
package com.wyl.redis.service.impl;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.map.MapUtil;
import com.wyl.redis.bean.DictionaryBean;
import com.wyl.redis.constant.DictionaryConst;
import com.wyl.redis.entity.FullCity;
import com.wyl.redis.service.DictionaryOperate;
import com.wyl.redis.service.FullCityService;
import com.wyl.redis.vo.FullCityVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author WuYiLong
 * @Date 2024/7/3 17:36
 */
@Slf4j
@Service
public class FullCityOperate implements DictionaryOperate {

    @Autowired
    private FullCityService fullCityService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public List list(String key) {
        if(!redisTemplate.hasKey(key)) {
            List<FullCity> list = fullCityService.list();
            List<DictionaryBean> dictionaryBeans = list.stream().map(m -> {
                DictionaryBean dictionaryBean = new DictionaryBean();
                dictionaryBean.setCode(m.getCode());
                dictionaryBean.setName(m.getName());
                dictionaryBean.setLevel(m.getLevel());
                dictionaryBean.setParentCode(m.getParentCode());
                return dictionaryBean;
            }).collect(Collectors.toList());
            redisTemplate.opsForValue().set(key,dictionaryBeans);
            return dictionaryBeans;
        }
        List<DictionaryBean> list = (List<DictionaryBean>)redisTemplate.opsForValue().get(key);
        return list;
    }

    @Override
    public List<Tree<String>> tree(String key) {
        if(!redisTemplate.hasKey(key)) {
            List<FullCity> list = fullCityService.list();
            List<Tree<String>> build = TreeUtil.build(list, "0", (t1, t2) -> {
                t2.setId(t1.getCode());
                t2.setName(t1.getName());
                t2.setParentId(t1.getParentCode());
            });
            redisTemplate.opsForValue().set(key,build);
            return build;
        }
        List<Tree<String>> trees = (List<Tree<String>>)redisTemplate.opsForValue().get(key);
        return trees;
    }

    @Override
    public String codeNameMap(String key, String code) {
        if(!redisTemplate.opsForHash().hasKey(key,code)) {
            FullCityVo fullCityVo = fullCityService.getByCode(code);
            if(fullCityVo != null) {
                redisTemplate.opsForHash().putIfAbsent(key,fullCityVo.getCode(),fullCityVo.getName());
                return fullCityVo.getName();
            }
            return null;
        }
        String name = (String)redisTemplate.opsForHash().get(key, code);
        return name;
    }

    @Override
    public String nameCodeMap(String key, String name) {
        if(!redisTemplate.opsForHash().hasKey(key,name)) {
            FullCityVo fullCityVo = fullCityService.getByFullName(name);
            if(fullCityVo != null) {
                redisTemplate.opsForHash().putIfAbsent(key,fullCityVo.getFullName(),fullCityVo.getCode());
                return fullCityVo.getCode();
            }
            return null;
        }
        String code = (String)redisTemplate.opsForHash().get(key, name);
        return code;
    }

    @Override
    public String supportType() {
        return DictionaryConst.FULL_CITY;
    }
}

package com.wyl.redis.service.impl;

import cn.hutool.core.lang.tree.Tree;
import com.wyl.redis.constant.DictionaryConst;
import com.wyl.redis.exception.BusinessException;
import com.wyl.redis.service.DictionaryOperate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @Description
 * @Author WuYiLong
 * @Date 2024/7/3 17:23
 */
@Slf4j
@Component
public class DictionaryService implements ApplicationContextAware {

    private Map<String,DictionaryOperate>  dictionaryMaps = new HashMap<>();

    @Autowired
    private RedisTemplate redisTemplate;

    public DictionaryOperate buildDictionaryOperate(String key) {
        DictionaryOperate dictionaryOperate = dictionaryMaps.get(key);
        if(dictionaryOperate == null) {
            throw new BusinessException("字典的key不存在");
        }
        return dictionaryOperate;
    }

    public List list(String key) {
        String listKey = DictionaryConst.DIC+key+DictionaryConst.LIST;
        if(key.contains(":")) {
            String[] split = key.split(":");
            key = split[0];
            listKey = DictionaryConst.DIC+key+DictionaryConst.LIST+":"+split[1];
        }
        List list = buildDictionaryOperate(key).list(listKey);
        return list;
    }

    public List<Tree<String>> tree(String key) {
        String listKey = DictionaryConst.DIC+key+DictionaryConst.TREE;
        if(key.contains(":")) {
            String[] split = key.split(":");
            key = split[0];
            listKey = DictionaryConst.DIC+key+DictionaryConst.TREE+":"+split[1];
        }
        List<Tree<String>> tree =buildDictionaryOperate(key).tree(listKey);
        return tree;
    }

    public String codeNameMap(String key, String code) {
        String name = buildDictionaryOperate(key).codeNameMap(DictionaryConst.DIC+key+":codeNameMap", code);
        return name;
    }

    public String nameCodeMap(String key, String name) {
        String code = buildDictionaryOperate(key).nameCodeMap(DictionaryConst.DIC+key+":nameCodeMap", name);
        return code;
    }

    public void refresh() {
        Set keys = redisTemplate.keys("dic*");
        keys.forEach(v->{
            redisTemplate.delete(v);
        });
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, DictionaryOperate> dictionaryOperateMap = applicationContext.getBeansOfType(DictionaryOperate.class);
        dictionaryOperateMap.forEach((k,v)->{
            dictionaryMaps.put(v.supportType(),v);
        });
    }
}

controller层
package com.wyl.redis.controller;

import com.wyl.common.bean.ResponseData;
import com.wyl.redis.service.impl.DictionaryService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 *
 * @Description
 * @Author WuYiLong
 * @Date 2024/7/8 10:21
 */
@Api(tags = "字典api")
@RestController
@RequestMapping(value = "dictionary")
public class DictionaryController {

    @Autowired
    private DictionaryService dictionaryService;

    @ApiOperation(value = "字典刷新")
    @GetMapping(value = "refresh")
    public ResponseData refresh() {
        dictionaryService.refresh();
        return ResponseData.success();
    }

    @ApiOperation(value = "字典列表")
    @GetMapping(value = "list")
    public ResponseData list(String key) {
        return ResponseData.successInstance(dictionaryService.list(key));
    }

    @ApiOperation(value = "字典树")
    @GetMapping(value = "tree")
    public ResponseData tree(String key) {
        return ResponseData.successInstance(dictionaryService.tree(key));
    }

    @ApiOperation(value = "根据code获取名称")
    @GetMapping(value = "codeNameMap")
    public ResponseData codeNameMap(String key, String code) {
        return ResponseData.successInstance(dictionaryService.codeNameMap(key,code));
    }

    @ApiOperation(value = "根据名称获取code")
    @GetMapping(value = "nameCodeMap")
    public ResponseData nameCodeMap(String key, String name) {
        return ResponseData.successInstance(dictionaryService.nameCodeMap(key, name));
    }
}

测试

根据code获取名称

image.png

字典列表

image.png

字典树

image.png

字典在redis客户端的存储

image.png

项目说明

只需要配置好本地的数据库,连接上自己本地的redis,启动项目,就会自动初始化数据库脚本到本地数据库。

package com.wyl.redis.config;

import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import com.baomidou.dynamic.datasource.support.ScriptRunner;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.Map;

/**
 * @Description 公共初始化配置
 * @Author WuYiLong
 * @Date 2024/7/8 9:38
 */
@Slf4j
@ConditionalOnProperty(prefix = "init",value = "enabled",havingValue = "true")
@Component
public class InitConfig implements ApplicationRunner {

    @Autowired
    private DynamicDataSourceProperties dynamicDataSourceProperties;
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("****************初始化数据库脚本开始*************");
        Map<String, DataSourceProperty> datasource = dynamicDataSourceProperties.getDatasource();
        DataSourceProperty master = datasource.get("master");
        DataSource build = DataSourceBuilder
                .create()
                .url(master.getUrl())
                .driverClassName(master.getDriverClassName())
                .password(master.getPassword())
                .type(master.getType())
                .username(master.getUsername())
                .build();

        ScriptRunner scriptRunner = new ScriptRunner(true, ";");
        scriptRunner.runScript(build,"classpath:/db/**");
        log.info("****************初始化数据库脚本结束*************");

    }
}

在配置文件那里配置,设置init.enabled=true

init:
  enabled: false

项目地址

github

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1944526.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

React 学习——条件渲染、遍历循环、事件绑定

React特点&#xff1a; 声明式的设计高效&#xff0c;采用虚拟DOM来实现DOM的渲染&#xff0c;最大限度减少DOM的操作灵活&#xff0c;跟其他库灵活搭配使用JSX&#xff0c;俗称JS里面写HTML&#xff0c;JavaScript语法的扩展组件化&#xff0c;模块化&#xff0c;代码容易复用…

SQL labs-SQL注入(二)

环境搭建参考 SQL注入&#xff08;一&#xff09; 一&#xff0c;SQL labs-less2。 http://192.168.61.206:8001/Less-2/?id-1 union select 1,2,group_concat(username , password) from users-- 与第一关没什么太大的不同&#xff0c;唯一区别就是闭合方式为数字型。 二…

苹果笔记本电脑如何优化系统 苹果电脑系统优化软件哪个好 cleanmymac x怎么用

随着时间的推移&#xff0c;你可能会发现你的MacBook运行速度变慢&#xff0c;甚至在执行一些基本任务时也会感觉到卡顿。这不仅影响了工作效率&#xff0c;也大大降低了使用体验。但别担心&#xff0c;优化你的Mac系统比做早餐还简单。本文将用一种轻松的风格向你介绍7种简单易…

AI绘画入门实践|Midjourney:使用 --seed 制作情侣头像与漫画

在 Midjourney 中&#xff0c;seed 是指一个种子&#xff0c;用于生成图像时的起点或基础。 使用格式&#xff1a;--seed 获取的seed值 获取 seed 值 使用 seed 生成图像 a cute boys avatar, background with blue sky and white cloud, Ghibli Studio style, Hayao Miyazaki…

2024最新手机软件APP下载排行网站源码 软件下载站PHP源码

源码介绍 这是一款简洁蓝色的手机软件下载应用排行、平台和最新发布网站源码&#xff0c;主要包括主页、APP列表页、APP详情介绍页、新闻资讯列表、新闻详情页、关于我们等模块页面。 软件下载站PHP网站源码&#xff0c;简单的部署上线&#xff0c;访问首页安装程序&#xff…

Docker Desktop安装

0 Preface/Foreward 1 安装 1.1 运行docker安装包 安装完Docker Desktop后&#xff0c;运行Docker Desktop&#xff0c;出现WSL 2安装不完整情况&#xff0c;具体情况如下&#xff1a; 解决方法&#xff1a;旧版 WSL 的手动安装步骤 | Microsoft Learn 也可以直接下载新的安…

rce漏洞-ctfshow(50-70)

Web51 if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\|\%|\x09|\x26/i", $c)){ system($c." >/dev/null 2>&1"); } Nl&#xff0c;绕过tac&#xff0c;cat&#xff0c;绕…

YOLOv8高效涨点之改进主干RepLKNet

这篇文章讨论了在现代卷积神经网络(CNN)设计中使用大卷积核的优势,并提出了一种新的CNN架构RepLKNet。以下是对文章内容的分条说明: 大卷积核的优势:文章提出使用大卷积核(例如3131)而不是传统的小卷积核(如33)可以提供更强大的特征提取能力。 灵感来源:这种设计思路…

AI智能名片微信小程序在品牌战略与私域流量构建中的应用与深度探索

摘要&#xff1a;在数字经济时代&#xff0c;私域流量的价值日益凸显&#xff0c;成为企业和个人实现可持续增长的重要驱动力。品牌&#xff0c;作为私域流量的核心&#xff0c;其稳定性和影响力直接关系到流量的质量与转化效率。AI智能名片微信小程序&#xff0c;作为数字营销…

耳机、音响UWB传输数据模组,飞睿智能低延迟、高速率超宽带uwb模块技术音频应用

在数字化浪潮席卷全球的今天&#xff0c;无线通信技术日新月异&#xff0c;其中超宽带&#xff08;Ultra-Wideband&#xff0c;简称UWB&#xff09;技术以其独特的优势&#xff0c;正逐步成为无线传输领域的新星。本文将深入探讨飞睿智能UWB传输数据模组在音频应用中的创新应用…

【故障排除】Unity在编辑器模式下Play时闪退

一开始以为是偶然的情况&#xff0c;但逐渐发现了规律&#xff1a; 每次某个角色释放技能的时候就会闪退。 为了找到问题代码&#xff0c;找了一下存放运行Log的文件夹&#xff1a; 打开 Console 窗口&#xff08;菜单&#xff1a;Window > General > Console&#xff…

修改 Tomcat 默认端口号最简单的方法

前言 每次在创建一个新的Maven项目之后&#xff0c;启动项目总会报8080端口号被占用的问题&#xff0c;既然每次都有这样的困扰&#xff0c;那不如一了百了&#xff0c;直接修改默认的8080端口号。 &#xff08;如果还是想要默认端口号。可参考我主页文章杀死占用了8080的进程…

使用UDP套接字编程详解【C语言】

UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;是一种面向无连接的传输层协议&#xff0c;用于在计算机网络上发送数据。它与 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;相比具有轻量、高效的特点&…

redis原理之底层数据结构-跳表

1.什么是跳表 1.1 链表及其不足 链表是在程序设计中最常见的数据结构之一&#xff0c;它通过指针将多个链表节点连接起来&#xff0c;这样就可以将逻辑上同一类的数据存储到不连续的内存空间上。链表结构如下&#xff1a; 但是链表有一个问题&#xff0c;就是当链表需要查询一…

JSON 文件第一段飘红

问题 原因 这个问题通常发生在尝试用 ESLint 去解析 JSON 文件时。ESLint 主要设计用于检查 JavaScript 代码的语法和风格&#xff0c;而JSON是一种数据交换格式&#xff0c;不包含 JavaScript 的逻辑结构&#xff0c;如函数、变量声明等。 解释报错原因 当ESLint遇到它不能识…

Nginx 如何处理 WebSocket 连接?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01; 文章目录 Nginx 如何处理 WebSocket 连接&#xff1f;一、WebSocket 连接简介二、Nginx 处理 WebSocket 连接的基本原理三、配置 Nginx 支持 WebSocket 连接四、Nginx 中的…

MyBatis-Plus的基本使用(一)

目录 前言 特性 MyBatis-Plus入门案例 常用注解 小结 前言 这篇文章主要来学习MyBatis-Plus这个非常强大的框架. 在学习MyBatis-Plus之前,需要有MyBatis的学习基础.因为MyBatis -Plus 是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#x…

Window下安装Zookeeper

一、下载 地址&#xff1a;https://archive.apache.org/dist/zookeeper/zookeeper-3.5.6/ 解压&#xff1a;非中文、没有空格目录下 新建data目录&#xff0c;用于存放数据文件 二、配置 进入conf目录&#xff0c;复制zoo_sample.cfg 为zoo.cfg 打开zoo.cfg 修改dataDir&…

PyTorch基于注意力的目标检测模型DETR

【图书推荐】《PyTorch深度学习与计算机视觉实践》-CSDN博客 目标检测是计算机视觉领域的一个重要任务&#xff0c;它的目标是在图像或视频中识别并定位出特定的对象。在这个过程中&#xff0c;需要确定对象的位置和类别&#xff0c;以及可能存在的多个实例。 DETR模型通过端…

2.3 大模型硬件基础:AI芯片(上篇) —— 《带你自学大语言模型》系列

本系列目录 《带你自学大语言模型》系列部分目录及计划&#xff0c;完整版目录见&#xff1a;带你自学大语言模型系列 —— 前言 第一部分 走进大语言模型&#xff08;科普向&#xff09; 第一章 走进大语言模型 1.1 从图灵机到GPT&#xff0c;人工智能经历了什么&#xff1…