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

一、背景

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

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

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

二、设计

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

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

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

三、代码

controller

Java 复制代码
@RestController
@RequestMapping("/pre_cook/client/address")
public class AddressClientController {

    @Resource
    private AddressClientService addressClientService;


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


}

impl实现类

Java 复制代码
@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​​工具类方法

Java 复制代码
    /**
     * 获取列表指定范围内的元素
     *
     * @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秒多

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

第三次,耗时200多毫秒

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

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

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

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

相关推荐
小安运维日记1 小时前
Linux云计算 |【第四阶段】NOSQL-DAY1
linux·运维·redis·sql·云计算·nosql
kejijianwen2 小时前
JdbcTemplate常用方法一览AG网页参数绑定与数据寻址实操
服务器·数据库·oracle
编程零零七3 小时前
Python数据分析工具(三):pymssql的用法
开发语言·前端·数据库·python·oracle·数据分析·pymssql
高兴就好(石6 小时前
DB-GPT部署和试用
数据库·gpt
这孩子叫逆6 小时前
6. 什么是MySQL的事务?如何在Java中使用Connection接口管理事务?
数据库·mysql
Karoku0666 小时前
【网站架构部署与优化】web服务与http协议
linux·运维·服务器·数据库·http·架构
码农郁郁久居人下6 小时前
Redis的配置与优化
数据库·redis·缓存
MuseLss8 小时前
Mycat搭建分库分表
数据库·mycat
Hsu_kk8 小时前
Redis 主从复制配置教程
数据库·redis·缓存
DieSnowK8 小时前
[Redis][环境配置]详细讲解
数据库·redis·分布式·缓存·环境配置·新手向·详细讲解