Redis实践—全国地址信息缓存

news2024/12/23 4:45:50

一、背景

在涉及全国地址的应用中,地址信息通常被频繁地查询和使用,例如电商平台、物流系统等。为了提高系统性能和减少对数据库的访问压力,可以使用缓存来存储常用的地址信息,其中 Redis 是一个非常流行的选择。

本次在一个企业入驻场场景中,需要选择企业服务区域,用户经常需要查询和使用全国省市地址信息(如下所示)。

如果每次查询都直接访问数据库,会增加数据库的负载,尤其是在高并发情况下。相较于其他数据,地址信息相对稳定,通常不会频繁变动。通过缓存常用的地址信息,可以加快查询速度,提高系统性能。

image

二、设计

数据库:字段及数据如下(需要sql文件,可私信联系)

image

Redis:使用List数据类型,把每条地址对象转换为json格式,存到Redis。

避免数据库更新,而缓存是老数据,导致数据不一致。设置过期时间7天,超过7天删除缓存,查询最新库中数据

image

三、代码

controller

image

@RestController
@RequestMapping("/pre_cook/client/address")
public class AddressClientController {

    @Resource
    private AddressClientService addressClientService;


    /**
     * 全国地址查询
     *
     * @return
     */
    @PostMapping("/list")
    public List<AddressVO> addressList() {
        return addressClientService.addressList();
    }


}

impl实现类

image

@Override
    public List<AddressVO> addressList() {

        String addressKey = AddressEnum.Address_PREFIX.getValue();
        Boolean exist = redisUtil.hasKey(addressKey);

        //1.如果缓存有数据,取缓存数据
        if (exist) {
            List<String> jsonList = redisUtil.lRange(addressKey, 0, -1);
            log.info("缓存查询地址信息-json格式:{}", jsonList);

            List<AddressVO> addressVOS = jsonList.stream()
                    .map(json -> JSON.parseObject(json, AddressVO.class))
                    .collect(Collectors.toList());
            return addressVOS;
        }


        //2.缓存无数据,查询数据库
        List<AddressInfoDO> infoDOList = addressInfoService.lambdaQuery()
                .in(AddressInfoDO::getLevel, CompanyConstant.COUNTRY_LEVEL, CompanyConstant.PROVINCE_LEVEL, CompanyConstant.CITY_LEVEL, CompanyConstant.DISTRICT_LEVEL)
                .eq(AddressInfoDO::getStatus, CompanyConstant.ADDRESS_ENABLED)
                .eq(AddressInfoDO::getEnableFlag, EnableFlagEnum.ENABLE.getCode())
                .list();

        List<AddressVO> addressVOS = infoDOList.stream().
                map(e -> AddressVO.builder()
                        .id(e.getId())
                        .addressCode(e.getCode())
                        .addressName(e.getName())
                        .level(e.getLevel())
                        .parentCode(e.getParentCode())
                        .key(PinYinUtils.getStringFirstName(e.getName()))
                        .build()
                ).collect(Collectors.toList());


        List<AddressVO> voList = addressVOS.stream()
                .sorted(Comparator
                        .comparingInt(AddressVO::getLevel)
                        .thenComparing(AddressVO::getKey, (s1, s2) -> s1.compareToIgnoreCase(s2)))
                .collect(Collectors.toList());

        //2.2存入缓存
        List<String> jsonList = voList.stream()
                .map(AddressVO -> JSON.toJSONString(AddressVO))
                .collect(Collectors.toList());

        redisUtil.lRightPushAll(addressKey, jsonList);
        redisUtil.expire(addressKey, DigitalConstant.SEVEN, TimeUnit.DAYS);

        return voList;
    }

RedisUtil​​工具类方法

    /**
     * 获取列表指定范围内的元素
     *
     * @param key   key
     * @param start 开始位置, 0是开始位置
     * @param end   结束位置, -1返回所有
     * @return
     */
    public List<String> lRange(String key, long start, long end) {
        return redisTemplate.opsForList().range(key, start, end);
    }



    /**
     * @param key   key
     * @param value val
     * @return
     */
    public Long lRightPushAll(String key, Collection<String> value) {
        return redisTemplate.opsForList().rightPushAll(key, value);
    }



    /**
     * 设置过期时间
     *
     * @param key     key
     * @param timeout
     * @param unit
     * @return
     */
    public Boolean expire(String key, long timeout, TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }

四、测试

第一次,查数据库,耗时4秒多

image

第二次,通过第一次查询,redis已存有数据,只需要200多毫秒

image

第三次,耗时200多毫秒

image

第四次,删除缓存,再次查库,耗时700多毫秒

image

通过上述测试,第一次查询Mysql数据库,耗时4秒多,后续查询耗时700多毫秒,说明MySQL 也有自身的缓存机制,其中包括查询缓存。

由于查询缓存的存在,第一次执行某个查询时可能会比较慢,因为需要执行实际的查询操作并将结果存入缓存中。但是,当相同的查询再次执行时,如果查询的条件和数据没有发生变化,就可以直接从查询缓存中获取结果,因此查询时间会明显减少。

这里使用Redis缓存,在首次从Mysql查询后,存入Redis。通过Redis查询,耗时只需200多毫秒,明显少于Mysql耗时,减轻了数据库压力,也可以支持更高的并发。

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

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

相关文章

【Text2SQL 经典模型】SQLNet

论文&#xff1a;SQLNet: Generating Structured Queries From Natural Language Without Reinforcement Learning ⭐⭐⭐⭐ Code: SQLNet | paperwithcodeSQLNet| GitHub 一、论文速读 这篇论文强调了一个问题&#xff1a;order-matters problem —— 意思是说&#xff0c;对…

【机器学习】—机器学习和NLP预训练模型探索之旅

目录 一.预训练模型的基本概念 1.BERT模型 2 .GPT模型 二、预训练模型的应用 1.文本分类 使用BERT进行文本分类 2. 问答系统 使用BERT进行问答 三、预训练模型的优化 1.模型压缩 1.1 剪枝 权重剪枝 2.模型量化 2.1 定点量化 使用PyTorch进行定点量化 3. 知识蒸馏…

HQL面试题练习 —— 品牌营销活动天数

题目来源&#xff1a;小红书 目录 1 题目2 建表语句3 题解 1 题目 有营销活动记录表&#xff0c;记录了每个品牌每次营销活动的开始日期和营销活动的结束日期&#xff0c;现需要统计出每个品牌的总营销天数。 注意&#xff1a; 1:苹果第一行数据的营销结束日期比第二行数据的营…

系统思考—跳出症状看全局

今年的《系统思考—跳出症状看全局》课程不断进行了迭代优化。通过一个企业的真实案例&#xff0c;我们与学员共同探讨了线性思考与系统思考的区别&#xff0c;并学习了如何从全局角度做出更加明智的决策&#xff0c;一切就绪&#xff0c;期待学员的共创。

xxe漏洞--xml外部实体注入漏洞

1.xxe漏洞介绍 XXE&#xff08;XML External Entity Injection&#xff09;是一种攻击技术&#xff0c;它允许攻击者注入恶意的外部实体到XML文档中。如果应用程序处理XML输入时未正确配置&#xff0c;攻击者可以利用这个漏洞访问受影响系统上的敏感文件、执行远程代码、探测内…

操作系统底层运行原理 —— 基于线程安全的消息机制

前言 学过Android应用开发的大概都知道Handler这个东东&#xff0c;这也是面试中老生常谈的问题。其实不仅仅是Android&#xff0c;iOS以及PC的操作系统&#xff0c;底层也离不开消息机制。这个属于生产消费者问题。 什么是生产者消费者模式 生产者消费者模式&#xff08;Pr…

【UE Websocket】“WebSocket Server”插件使用记录

1. 在商城中下载“WebSocket Server”插件 该插件具有如下节点&#xff0c;基本可以满足WebSocket服务端的所有需求 2. 如果想创建一个基本的服务端&#xff0c;我们可以新建一个actor蓝图&#xff0c;添加如下节点 3. UE运行后&#xff0c;我们可以使用在线的websocket测试助手…

使用MicroPython和pyboard开发板(15):使用LCD和触摸传感器

使用LCD和触摸传感器 pybaord的pyb对LCD设备也进行了封装&#xff0c;可以使用官方的LCD显示屏。将LCD屏连接到开发板&#xff0c;连接后。 使用LCD 先用REPL来做个实验&#xff0c;在MicroPython提示符中输入以下指令。请确保LCD面板连接到pyboard的方式正确。 >>…

认识NXP新型微处理器:MCX工业和物联网微控制器

目录 概述 1 MCX工业和物联网微控制器介绍 2 MCX 系列微控制器类型 2.1 MCX N系列微控制器 2.1.1 主要特征 2.1.2 MCX N系列产品 2.1.3 MCX N9xx和N5xx MCU选型表 2.2 MCX A系列微控制器 2.2.1 主要特征 2.2.2 MCX A系列产品 2.2.3 MCX A MCU的架构 2.3 MCX W系…

Unity射击游戏开发教程:(24)创造不同的敌人

在这篇文章中,我们将讨论添加一个可以承受多次攻击的新敌人和一些动画来使事情变得栩栩如生。敌人没有任何移动或射击行为。这将有助于增强未来敌人的力量。 我们将声明一个 int 来存储敌人可以承受的攻击数量,并将其设置为 3。

Unity修改Project下的Assets的子文件的图标

Unity修改文件夹的图标 示例&#xff1a; 在右键可以创建指定文件夹。 github链接 https://github.com/SeaeeesSan/SimpleFolderIconCSDN资源的链接 https://download.csdn.net/download/GoodCooking/89347361 去GitHub下载支持原作者哦。重要的事情 截图来自GitHub 。 U…

信息系统项目管理师0127:工具与技术(8项目整合管理—8.6管理项目知识—8.6.2工具与技术)

点击查看专栏目录 文章目录 8.6.2 工具与技术8.6.2 工具与技术 专家判断管理项目知识过程中,应征求具备如下领域相关专业知识或接受过相关培训的个人或小组的意见,涉及的领域包括:知识管理、信息管理、组织学习、知识和信息管理工具以及来自其他项目的相关信息等。 知识管理…

【2024】高校网络安全管理运维赛

比赛时间&#xff1a;2024-05-06 Re-easyre 基本的base64换表&#xff0c;用CyberChef解密 Re-babyre 进入主函数&#xff0c;发现输入四次 看一下就知道是大数求解 (当初写的时候差不多 不知道为什么第四个总是算错…) from z3 import *s Solver() # 设置一个解方程的类…

产品经理-需求收集(二)

1. 什么是需求 指在一定的时期中&#xff0c;一定场景中&#xff0c;无论是心理上还是生理上的&#xff0c;用户有着某种“需要”&#xff0c;这种“需要”用户自己不一定知道的&#xff0c;有了这种“需要”后用户就有做某件事情的动机并促使达到其某种目的&#xff0c;这也就…

Redis 主从复制、哨兵与集群

一、Redis 主从复制 1. 主从复制的介绍 主从复制&#xff0c;是指将一台Redis服务器的数据&#xff0c;复制到其他的Redis服务器。前者称为主节点(Master)&#xff0c;后者称为从节点(Slave)&#xff1b;数据的复制是单向的&#xff0c;只能由主节点到从节点。 默认情况下&a…

如何快速从手动测试转向自动化测试

寻求具有无缝持续集成和持续交付 (CI/CD) 的高效 DevOps 管道比以往任何时候都更加重要。想象一下这样一个场景&#xff1a;您的软件组织显著减少了人工工作量、降低了成本&#xff0c;并更加自信地发布了软件更新。换句话说&#xff0c;通过将 Web UI 和 API 测试结合在一起&a…

展现金融科技前沿力量,ATFX于哥伦比亚金融博览会绽放光彩

不到半个月的时间里&#xff0c;高光时刻再度降临ATFX。而这一次&#xff0c;是ATFX不曾拥有的桂冠—“全球最佳在线经纪商”(Best Global Online Broker)。2024年5月15日至16日&#xff0c;拉丁美洲首屈一指的金融盛会—2024年哥伦比亚金融博览会(Money Expo Colombia 2024) 于…

前端开发攻略---用Vue实现无限滚动的几种方法

目录 1、原理 2、使用CSS动画 代码&#xff1a; 3、使用JS实现 代码&#xff1a; 1、原理 复制内容&#xff1a;将需要滚动的内容复制一次&#xff0c;并将这些副本放置在原始内容的后面。这样&#xff0c;当用户滚动到内容的末尾时&#xff0c;就会无缝地切换回到内容的起…

【Python】—— 公共的方法

目录 &#xff08;一&#xff09;公共操作 1.1 公共操作之运算符加号 1.2 公共操作之运算符乘号 1.3 公共操作之运算符判断数据是否存在 &#xff08;二&#xff09;公共方法 2.1 公共方法-len 2.2 公共方法-del 2.3 公共方法-max和min 2.4 公共方法-range 2.5 公共方…

如果 SEC 批准以太坊现货 ETF,会有更多山寨币 ETF 吗?

撰文&#xff1a;Protos 编译&#xff1a;Ismay&#xff0c;BlockBeats 文章来源香港Web3媒体Techun News 编者按&#xff1a;SEC 已与交易平台和 ETF 申请人就 19b-4 规则变更请求进行沟通&#xff0c;这表明以太坊现货 ETF 获批的可能性大大增加。与此同时山寨币投资者猜测…