springboot集成redis之字典缓存

什么是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;@Overridepublic 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 {@Autowiredprivate FullCityService fullCityService;@Autowiredprivate RedisTemplate redisTemplate;@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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<>();@Autowiredprivate 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);});}@Overridepublic 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 {@Autowiredprivate 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 {@Autowiredprivate DynamicDataSourceProperties dynamicDataSourceProperties;@Overridepublic 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.rhkb.cn/news/382294.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Postman设置全部请求都携带请求头,Postman如何一次性设置请求头、不需要一个请求一个请求去添加请求头

文章目录 一、问题描述二、解决办法三、应用场景 一、问题描述 现在我有 n 个接口测试&#xff0c;其中 n 个都需要携带一致的请求头&#xff08;其实一般都是携带 JWT 令牌&#xff09;&#xff0c;怎么办&#xff1f;我要一个一个写&#xff1f;如图&#xff1a; 二、解决办…

go语言Gin框架的学习路线(十)

目录 GORM的CRUD教程 查询 普通查询 定义 User 结构体 查询所有用户 查询第一个用户 总结 条件查询 内联条件 额外查询选项 高级查询 链式操作 Scopes 多个立即执行方法 GORM的CRUD教程 CRUD 是 "Create, Read, Update, Delete"&#xff08;创建、查询…

[经验] 驰这个汉字的拼音是什么 #学习方法#其他#媒体

驰这个汉字的拼音是什么 驰&#xff0c;是一个常见的汉字&#xff0c;其拼音为“ch”&#xff0c;音调为第四声。它既可以表示动词&#xff0c;也可以表示形容词或副词&#xff0c;意义广泛&#xff0c;经常出现在生活和工作中。下面就让我们一起来了解一下“驰”的含义和用法。…

以Zookeeper为例 浅谈脑裂与奇数节点问题

一、脑裂现象的定义与影响 脑裂&#xff08;split-brain&#xff09;是指在分布式系统中&#xff0c;因网络分区或其他故障导致系统被切割成两个或多个相互独立的子系统&#xff0c;每个子系统可能独立选举出自己的领导节点。这一现象在依赖中心领导节点&#xff08;如Elastic…

【Qt 】JSON 数据格式详解

文章目录 1. JSON 有什么作用?2. JSON 的特点3. JSON 的两种数据格式3.1 JSON 数组3.2 JSON 对象 4. Qt 中如何使用 JSON 呢&#xff1f;4.1 QJsonObject4.2 QJsonArray4.3 QJsonValue4.4 QJsonDocument 5. 构建 JSON 字符串6. 解析 JSON 字符串 1. JSON 有什么作用? &#x…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第三十九章 Linux MISC驱动

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

5.Fabric的共识机制

在Fabric中,有以下3中典型共识机制。 Solo共识 solo共识机制只能用于单节点模式,即只能有一个Orderer节点,因此,其共识过程很简单,每接收到一个交易信息,就在共识模块的控制下产生区块并广播给节点存储到账本中。 Solo 模式下的共识只适用于一个Orderer节点,所以可以在…

CTF-Web习题:2019强网杯 UPLOAD

题目链接&#xff1a;2019强网杯 UPLOAD 解题思路 打开靶场如下图所示&#xff0c;是一个注册和登录界面 那就注册登录一下&#xff0c;发现是一个提交头像的页面&#xff1a; 试了一下只有能正确显示的png图片才能提交成功&#xff0c;同时F12拿到cookie&#xff0c;base6…

便宜多域名SSL证书申请平台推荐

随着互联网的深入发展&#xff0c;网络安全问题愈发受到重视。SSL证书作为保障网站和用户数据安全的重要工具&#xff0c;其重要性不言而喻。在众多SSL证书类型中&#xff0c;多域名SSL证书因其独特的功能和优势&#xff0c;逐渐成为企业和个人保护网站安全的首选。 申请便宜S…

Django视图与URLs路由详解

在Django Web框架中&#xff0c;视图&#xff08;Views&#xff09;和URLs路由&#xff08;URL routing&#xff09;是Web应用开发的核心概念。它们共同负责将用户的请求映射到相应的Python函数&#xff0c;并返回适当的响应。本篇博客将深入探讨Django的视图和URLs路由系统&am…

全国区块链职业技能大赛国赛考题区块链产品需求分析与方案设计

任务1-1:区块链产品需求分析与方案设计 本任务需要依据项目背景完成需求分析与方案设计,具体要求如下: 依据给定区块链食品溯源系统的业务架构图,对考题进行业务分析,尽可能多的去考虑一个业务系统所需要的模块,使用Visio或思维导图工具展现本系统的基本设计概念和处理流…

科研绘图系列:R语言热图(heatmap)

介绍 热图是一种数据可视化技术,通常用于展示数据的分布情况。它通过颜色的变化来表示数据的大小或密度,使得观察者能够直观地理解数据集中的模式和趋势。以下是热图的一些关键特点和应用场景: 数据分布:热图可以显示数据在不同区域的分布情况,比如在地图上显示不同地区的…

Go基础编程 - 12 -流程控制

流程控制 1. 条件语句1.1. if...else 语句1.2. switch 语句1.3. select 语句1.3.1. select 语句的通信表达式1.3.2. select 的基特性1.3.3. select 的实现原理1.3.4. 经典用法1.3.4.1 超时控制1.3.4.2 多任务并发控制1.3.4.3 监听多通道消息1.3.4.4 default 实现非堵塞读写 2. …

GPT-4o mini是什么?

今天&#xff0c;全网都知道 OpenAI 发现货了&#xff01; GPT-4o mini 取代 GPT 3.5&#xff0c;从此坐上正主之位。 从官网信息来看&#xff0c;OpenAI 最新推出的 GPT-4o mini 重新定义了 AI 成本效益的标准&#xff0c;其性能优于前代模型 GPT-3.5 Turbo&#xff0c;且成本…

查看公网IP的网络出口

文章目录 背景 背景 有时候在各种交易或其他时候&#xff0c;会被问到给我一个公网IP&#xff0c;我来帮你加白名单。 这个怎么怎么获取公网IP呢&#xff0c;在自己本机查看ipconfig或者ifconfig ip a 等命令查到的一般都是局域网的IP&#xff0c;每台机器都需要一个IP来进行对…

数学建模学习(111):改进遗传算法(引入模拟退火、轮盘赌和网格搜索)求解JSP问题

文章目录 一、车间调度问题1.1目前处理方法1.2简单案例 二、基于改进遗传算法求解车间调度2.1车间调度背景介绍2.2遗传算法介绍2.2.1基本流程2.2.2遗传算法的基本操作和公式2.2.3遗传算法的优势2.2.4遗传算法的不足 2.3讲解本文思路及代码2.4算法执行结果&#xff1a; 三、本文…

基于MobileNetv2的垃圾分类函数式自动微分-昇思25天打卡

基于MobileNetv2的垃圾分类 本文档主要介绍垃圾分类代码开发的方法。通过读取本地图像数据作为输入&#xff0c;对图像中的垃圾物体进行检测&#xff0c;并且将检测结果图片保存到文件中。 1、实验目的 了解熟悉垃圾分类应用代码的编写&#xff08;Python语言&#xff09;&a…

linux 网络子系统

__netif_receive_skb_core 是 Linux 内核网络子系统中一个非常重要的函数&#xff0c;它负责将网络设备驱动层接收到的数据包传递到上层协议栈进行处理。以下是对该函数的一些关键点的详细解析&#xff1a; 一、函数作用 __netif_receive_skb_core 函数是处理接收到的网络数据…

linux 解决端口占用

1.查询被占用的端口 netstat -tln | grep 60602.查询该端口对应的服务 lsof -i :60603.杀死该进程 //14868是第二步的PID kill -9 14868