项目实战中redis和数据库结合提升缓存效率

1.缓存初始化

这一步需要将数据库中所有的有效数据写入到redis缓存

java 复制代码
package org.dsk.dragon.business.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.gitee.loulan_yxq.owner.core.bean.BeanTool;
import io.gitee.loulan_yxq.owner.core.collection.ArrayTool;
import io.gitee.loulan_yxq.owner.core.collection.CollTool;
import io.gitee.loulan_yxq.owner.core.tool.ObjectTool;
import org.dsk.dragon.business.api.domain.extend.StationDetailInfo;
import org.dsk.dragon.business.api.dto.station.StationLogicalComputeDTO;
import org.dsk.dragon.business.api.entity.BsStaActTag;
import org.dsk.dragon.business.api.entity.BsStaTags;
import org.dsk.dragon.business.api.vo.StaPageQueVO;
import org.loulan.application.dragon.common.core.config.redis.RedisKey;
import org.loulan.application.dragon.common.core.domain.extend.StationInfo;
import org.loulan.application.dragon.common.core.dto.StationCacheDTO;
import org.loulan.application.dragon.common.interfaces.service.system.DgStationClientService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * 站点信息缓存类
 * @ClassName StationInfoCache
 * @Author yangfeng
 * @Date 2025/11/4 11:36
 * @Version 1.0
 */
@Component
public class StationInfoCache {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private BsStationLngService bsStationLngService;
    @Resource
    private DgStationClientService stationClientService;
    @Async
    public void cache(){
        StaPageQueVO pageQueVO = new StaPageQueVO();
        pageQueVO.setPageCurrent(1);
        pageQueVO.setPageSize(10000);
        //缓存站点详细信息 hash
        Page<StationDetailInfo> stationPageList = bsStationLngService.getStationPageList(pageQueVO);
        Map<String,Object> stationMap = new HashMap<>();
        for (StationDetailInfo sta : stationPageList.getRecords()) {
            StationCacheDTO cacheDTO = BeanTool.copy(sta, StationCacheDTO.class);
            if(ArrayTool.isNotEmpty(sta.getCoord()) && sta.getCoord().length==2){
                String[] coord = sta.getCoord();
                cacheDTO.setLatitude(coord[0]);
                cacheDTO.setLongitude(coord[1]);
            }
            if(ObjectTool.isNotNull(sta.getGradeTotal()) && ObjectTool.isNotNull(sta.getGradeCount())){
                BigDecimal grade = sta.getGradeTotal().divide(BigDecimal.valueOf(sta.getGradeCount()), 1, RoundingMode.HALF_UP);
                cacheDTO.setGrade(grade.compareTo(new BigDecimal("3.6"))<0?new BigDecimal("3.6"):grade);
            }
            List<BsStaTags> staTags = sta.getStaTags();
            if(CollTool.isNotEmpty(staTags)){
                List<Integer> tags = staTags.stream().map(BsStaTags::getTagId).toList();
                if(CollTool.isNotEmpty(tags)){
                    cacheDTO.setServerCodes(tags);
                }
            }else {
                cacheDTO.setServerCodes(new ArrayList<>());
            }
            stationMap.put(sta.getId()+"",cacheDTO);
            redisTemplate.opsForHash().putAll(RedisKey.STATION_HASH,stationMap);
        }
    }

}

这一段代码的核心在于最后两行代码,将数据组成需要的格式后,统一使用一个设置命令将数据设置到redis缓存中

2.执行查询

java 复制代码
public CustomPage<StationDetailInfo> getStationPageListV1(StaPageQueVO vo) {
        Map<Object, Object> map = redisTemplate.opsForHash().entries(RedisKey.STATION_HASH);
        List<StationLogicalComputeDTO> sortResultList;
        List<StationLogicalComputeDTO> resultList = map.values().stream()
                .map(sta -> {
                    StationCacheDTO stationCacheDTO = (StationCacheDTO) sta;
                    StationLogicalComputeDTO stationLogicalComputeDTO = BeanTool.copy(stationCacheDTO, StationLogicalComputeDTO.class);

                    if (StrTool.isNotBlank(stationCacheDTO.getLongitude()) && StrTool.isNotBlank(stationCacheDTO.getLatitude())) {
                        Integer intDistance = DistanceUtils.getIntDistanceM(vo.getCoord()[1], vo.getCoord()[0],
                                stationCacheDTO.getLongitude(), stationCacheDTO.getLatitude(), 2);
                        stationLogicalComputeDTO.setDistance(intDistance);
                    } else {
                        stationLogicalComputeDTO.setDistance(Integer.MAX_VALUE);
                    }
                    return stationLogicalComputeDTO;
                })
                .collect(Collectors.toList());  // 直接收集到新的 List

        //距离范围和服务标签查询
        if(ObjectTool.isNotNull(vo.getDistanceQuery()) && !ObjectTool.equals(StationDistanceRangeQueryEnum.NO_LIMIT.getCode(),vo.getDistanceQuery() )){
            resultList = resultList.stream().filter(r -> r.getDistance()<=vo.getDistanceQuery()*1000)
                    .toList();
        }
        if(CollTool.isNotEmpty(vo.getServersQuery())){
            resultList = resultList.stream()
                    .filter(obj -> new HashSet<>(obj.getServerCodes()).containsAll(vo.getServersQuery()))
                    .toList();
        }
        if(ObjectTool.isNotNull(vo.getSelectTypeQuery()) && !ObjectTool.equals(StationSelectTypeEnum.ALL.getCode(), vo.getSelectTypeQuery())){
            resultList = resultList.stream().filter(s -> s.getSelectType().equals(vo.getSelectTypeQuery()))
                    .toList();
        }
        //名称或地址模糊查询
        if(StrTool.isNotBlank(vo.getNameOrAddressQuery())){
            resultList = resultList.stream()
                    .filter(sta-> (sta.getName() != null && sta.getName().contains(vo.getNameOrAddressQuery())) ||
                            (sta.getAddress() != null && sta.getAddress().contains(vo.getNameOrAddressQuery())))
                    .toList();
        }
        Comparator<StationLogicalComputeDTO> comparator = null;
        if(ObjectTool.isNotNull(vo.getSortType())){
            comparator = switch (vo.getSortType()) {
                case 1 -> StationSortBuilder.sortByDistance(null, false);
                case 2 -> StationSortBuilder.sortByGrade(null, true);
                case 3 -> StationSortBuilder.sortByPrice(null, false);
                case 4 -> StationSortBuilder.sortByPrice(null, true);
                default -> throw new IllegalArgumentException("非法的排序类型: " + vo.getSortType());
            };

        }else{
            comparator = StationSortBuilder.sortByDistance(null, false);
        }
        sortResultList = resultList.stream().sorted(comparator).toList();
        sortResultList.forEach(t->{
            log.info("站点Id{} 距离{} 评分{} 合力价{}",t.getId(),t.getDistance(),t.getGrade(),t.getHlPrice());
        });
        CustomPage<StationLogicalComputeDTO> customPage = new CustomPage<>((int) vo.getPageCurrent(), (int) vo.getPageSize(), sortResultList);
        List<StationLogicalComputeDTO> records = customPage.getRecords();
        if(CollTool.isNotEmpty(records)){
            List<Integer> stationIds = records.stream().map(StationLogicalComputeDTO::getId).toList();
            StationPageQueryVo queryVo = new StaPageQueVO();
            queryVo.setPageCurrent(vo.getPageCurrent());
            queryVo.setPageSize(vo.getPageSize());
            queryVo.setStationIds(stationIds);
            queryVo.setCoord(new String[]{vo.getCoord()[0],vo.getCoord()[1]});
            List<StationInfo> stationInfos = dgStationClientService.stationList(queryVo);
            List<StationDetailInfo> stationDetailInfos = BeanTool.copy(stationInfos, StationDetailInfo.class);
            this.setStationDetailInfos(stationDetailInfos);
            return customPage.resetRecords(stationDetailInfos);
        }
        return new CustomPage<>((int) vo.getPageCurrent(), (int) vo.getPageSize(), new ArrayList<>());
    }

代码核心逻辑说明

  1. 获取hash列表转为List
java 复制代码
 Map<Object, Object> map = redisTemplate.opsForHash().entries(RedisKey.STATION_HASH);
        List<StationLogicalComputeDTO> sortResultList;
        List<StationLogicalComputeDTO> resultList = map.values().stream()
                .map(sta -> {
                    StationCacheDTO stationCacheDTO = (StationCacheDTO) sta;
                    StationLogicalComputeDTO stationLogicalComputeDTO = BeanTool.copy(stationCacheDTO, StationLogicalComputeDTO.class);

                    if (StrTool.isNotBlank(stationCacheDTO.getLongitude()) && StrTool.isNotBlank(stationCacheDTO.getLatitude())) {
                        Integer intDistance = DistanceUtils.getIntDistanceM(vo.getCoord()[1], vo.getCoord()[0],
                                stationCacheDTO.getLongitude(), stationCacheDTO.getLatitude(), 2);
                        stationLogicalComputeDTO.setDistance(intDistance);
                    } else {
                        stationLogicalComputeDTO.setDistance(Integer.MAX_VALUE);
                    }
                    return stationLogicalComputeDTO;
                })
                .collect(Collectors.toList());  // 直接收集到新的 List
  1. 条件查询
java 复制代码
//距离范围和服务标签查询
        if(ObjectTool.isNotNull(vo.getDistanceQuery()) && !ObjectTool.equals(StationDistanceRangeQueryEnum.NO_LIMIT.getCode(),vo.getDistanceQuery() )){
            resultList = resultList.stream().filter(r -> r.getDistance()<=vo.getDistanceQuery()*1000)
                    .toList();
        }
        if(CollTool.isNotEmpty(vo.getServersQuery())){
            resultList = resultList.stream()
                    .filter(obj -> new HashSet<>(obj.getServerCodes()).containsAll(vo.getServersQuery()))
                    .toList();
        }
        if(ObjectTool.isNotNull(vo.getSelectTypeQuery()) && !ObjectTool.equals(StationSelectTypeEnum.ALL.getCode(), vo.getSelectTypeQuery())){
            resultList = resultList.stream().filter(s -> s.getSelectType().equals(vo.getSelectTypeQuery()))
                    .toList();
        }
        //名称或地址模糊查询
        if(StrTool.isNotBlank(vo.getNameOrAddressQuery())){
            resultList = resultList.stream()
                    .filter(sta-> (sta.getName() != null && sta.getName().contains(vo.getNameOrAddressQuery())) ||
                            (sta.getAddress() != null && sta.getAddress().contains(vo.getNameOrAddressQuery())))
                    .toList();
        }
  1. 排序
java 复制代码
Comparator<StationLogicalComputeDTO> comparator = null;
        if(ObjectTool.isNotNull(vo.getSortType())){
            comparator = switch (vo.getSortType()) {
                case 1 -> StationSortBuilder.sortByDistance(null, false);
                case 2 -> StationSortBuilder.sortByGrade(null, true);
                case 3 -> StationSortBuilder.sortByPrice(null, false);
                case 4 -> StationSortBuilder.sortByPrice(null, true);
                default -> throw new IllegalArgumentException("非法的排序类型: " + vo.getSortType());
            };

        }else{
            comparator = StationSortBuilder.sortByDistance(null, false);
        }
        sortResultList = resultList.stream().sorted(comparator).toList();
        sortResultList.forEach(t->{
            log.info("站点Id{} 距离{} 评分{} 合力价{}",t.getId(),t.getDistance(),t.getGrade(),t.getHlPrice());
        });

排序的工具类

java 复制代码
package org.dsk.dragon.business.config;

import org.dsk.dragon.business.api.dto.station.StationLogicalComputeDTO;

import java.util.Comparator;

/**
 * 站点信息排序构建器
 * @ClassName StationSortBuilder
 * @Author yangfeng
 * @Date 2025/11/6 14:24
 * @Version 1.0
 */
public class StationSortBuilder {
    public static Comparator<StationLogicalComputeDTO> sortByDistance(Comparator<StationLogicalComputeDTO> comparator, boolean isDesc){
        if (comparator != null) {
            if(isDesc){
                comparator = comparator.thenComparing(StationLogicalComputeDTO::getDistance, Comparator.reverseOrder());
            }else {
                comparator = comparator.thenComparing(StationLogicalComputeDTO::getDistance);
            }
        } else {
            if(isDesc){
                comparator = Comparator.comparing(StationLogicalComputeDTO::getDistance, Comparator.reverseOrder());
            }else{
                comparator = Comparator.comparing(StationLogicalComputeDTO::getDistance);
            }
        }
        return comparator;
    }
    public static Comparator<StationLogicalComputeDTO> sortByGrade(Comparator<StationLogicalComputeDTO> comparator, boolean isDesc){
        if (comparator != null) {
            if(isDesc){
                comparator = comparator.thenComparing(StationLogicalComputeDTO::getGrade, Comparator.reverseOrder());
            }else {
                comparator = comparator.thenComparing(StationLogicalComputeDTO::getGrade);
            }
        } else {
            if(isDesc){
                comparator = Comparator.comparing(StationLogicalComputeDTO::getGrade, Comparator.reverseOrder());
            }else{
                comparator = Comparator.comparing(StationLogicalComputeDTO::getGrade);
            }
        }
        return comparator;
    }
    public static Comparator<StationLogicalComputeDTO> sortByPrice(Comparator<StationLogicalComputeDTO> comparator, boolean isDesc){
        if (comparator != null) {
            if(isDesc){
                comparator = comparator.thenComparing(StationLogicalComputeDTO::getHlPrice, Comparator.reverseOrder());
            }else {
                comparator = comparator.thenComparing(StationLogicalComputeDTO::getHlPrice);
            }
        } else {
            if(isDesc){
                comparator = Comparator.comparing(StationLogicalComputeDTO::getHlPrice, Comparator.reverseOrder());
            }else{
                comparator = Comparator.comparing(StationLogicalComputeDTO::getHlPrice);
            }
        }
        return comparator;
    }
}
  1. 分页
java 复制代码
CustomPage<StationLogicalComputeDTO> customPage = new CustomPage<>((int) vo.getPageCurrent(), (int) vo.getPageSize(), sortResultList);
        List<StationLogicalComputeDTO> records = customPage.getRecords();

自定义分页工具类

java 复制代码
package org.dsk.dragon.business.util;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.List;

/**
 * @ClassName CustomPage
 * @Description TODO 自定义分页构造
 * @Author @yangfeng
 * @Date 2022/11/9 14:11
 * @Version 1.0
 */
@Data
@NoArgsConstructor
public class CustomPage<T> implements Serializable {

    private Integer current;
    private Integer size;
    private Integer startRow;
    private Integer endRow;
    private Integer pages;
    private List<T> records ;
    private Integer total;
    /**
     * @Author @yangfeng
     * @Description // 分页构造器返回对象
     * @Date 9:44 2022/11/7
     * @param current
     * @param size
     * @param totalList
     * @return
     * @return null
     **/
    public CustomPage(Integer current, Integer size, List<T> totalList) {
        this.current = current<=1 ? 1:current;
        this.size = size<=1 ? 1:size;
        this.total = totalList.size();
        if(CollectionUtils.isEmpty(totalList)){
            return ;
        }
        int totalCount = totalList.size();
        if(totalCount<=size){
            this.pages=1;
        }else{
            if(totalCount%size>0){
                this.pages = totalCount/size+1;
            }else{
                this.pages = totalCount/size;
            }
        }
        this.startRow = (this.current - 1) * this.size;
        this.endRow = this.startRow + this.size;
        if(endRow>totalCount)endRow=totalCount;
        this.records = totalList.subList(this.startRow,this.endRow);
    }

    public <R> CustomPage<R> resetRecords(List<R> newRecords) {
        CustomPage<R> newPage = new CustomPage<>();
        newPage.current = this.current;
        newPage.size = this.size;
        newPage.total = this.total;
        newPage.pages = this.pages;
        newPage.startRow = this.startRow;
        newPage.endRow = this.endRow;
        newPage.records = newRecords;
        return newPage;
    }



    /**
     * 自定义分页方法
     * @Param [page, totalList]
     * @return com.baomidou.mybatisplus.extension.plugins.pagination.Page
     * @Date 14:00 2023/8/11
     * @Author yangfeng
     **/
    public static Page getCustomPage(Page<?> page, List totalList){
        page.setTotal(totalList.size());
        if(CollectionUtils.isEmpty(totalList)){
            return page;
        }
        Integer totalCount = totalList.size();
        if(totalCount<=page.getSize()){
            page.setPages(1);
        }else{
            if(totalCount%page.getSize()>0){
                page.setPages(totalCount/page.getSize()+1) ;
            }else{
                page.setPages(totalCount/page.getSize()) ;
            }
        }
        Integer current = (int)page.getCurrent();
        Integer size = (int)page.getSize();

        int startRow = current>0?(current-1)*size:0;
        int endRow= startRow+size*(current>0?1:0);
        if(endRow>totalCount){
            endRow=totalCount;
        }
        totalList = totalList.subList(startRow,endRow);
        page.setRecords(totalList);
        return page;
    }


}
  1. 从数据库查询数据(保证根据传入的id按照顺序返回数据)
java 复制代码
if(CollTool.isNotEmpty(records)){
            List<Integer> stationIds = records.stream().map(StationLogicalComputeDTO::getId).toList();
            StationPageQueryVo queryVo = new StaPageQueVO();
            queryVo.setPageCurrent(vo.getPageCurrent());
            queryVo.setPageSize(vo.getPageSize());
            queryVo.setStationIds(stationIds);
            queryVo.setCoord(new String[]{vo.getCoord()[0],vo.getCoord()[1]});
            List<StationInfo> stationInfos = dgStationClientService.stationList(queryVo);
            List<StationDetailInfo> stationDetailInfos = BeanTool.copy(stationInfos, StationDetailInfo.class);
            this.setStationDetailInfos(stationDetailInfos);
            return customPage.resetRecords(stationDetailInfos);
        }
        return new CustomPage<>((int) vo.getPageCurrent(), (int) vo.getPageSize(), new ArrayList<>());

查询数据要保证按照传入的数据顺序返回,请参考如下具体实现:

xml 复制代码
    <select id="getStaList" resultType="org.loulan.application.dragon.common.core.domain.extend.StationInfo">
        select
        <include refid="Base_Column_List"/>
        <if test="vo.coord != null and vo.coord.length==2">
            ,earth_distance(ll_to_earth (cast(#{vo.coord[0]} as numeric),cast(#{vo.coord[1]} as numeric)),
            ll_to_earth(cast((regexp_split_to_array(coord, E','))[1] as numeric),cast((regexp_split_to_array(coord,
            E','))[2] as numeric))) as distance
        </if>
        from dg_station
        where del_flag=1
        <if test="vo.domainName != null and vo.domainName != ''">
            <bind name="domainNameLike" value="'%'+vo.domainName+'%'"/>
            AND domain_name LIKE #{domainNameLike}
        </if>
        <if test="vo.name != null and vo.name != ''">
            <bind name="nameLike" value="'%'+vo.name+'%'"/>
            AND ( name LIKE #{nameLike} OR address LIKE #{nameLike})
        </if>
        <if test="vo.operStatus != null">
            AND oper_status = #{vo.operStatus}
        </if>
        <if test="vo.selectType != null">
            AND select_type = #{vo.selectType}
        </if>
        <if test="vo.status != null">
            AND status = #{vo.status}
        </if>
        <if test="vo.type != null">
            AND type = #{vo.type}
        </if>
        <if test="vo.stationId != null">
            AND id = #{vo.stationId}
        </if>
        <if test="vo.stationIds != null and vo.stationIds.size() > 0">
            AND id IN
            <foreach item="item" index="index" collection="vo.stationIds" open="(" separator="," close=")">
                #{item}
            </foreach>
        </if>
        <if test="vo.isScore != null">
            AND is_score = #{vo.isScore}
        </if>
        <if test="vo.scoreCheckConf != null">
            AND score_check_conf = #{vo.scoreCheckConf}
        </if>
        <if test="vo.stationIds != null and vo.stationIds.size() > 0">
            ORDER BY
            <foreach item="item" index="index" collection="vo.stationIds" open="CASE" separator=" " close="END">
                WHEN id = #{item} THEN ${index + 1}
            </foreach>
        </if>
    </select>

3.缓存更新

缓存更新使用手动设置和aop方式设置更新

手动设置是针对新增的情况,因为更新缓存是基于主键id查询数据库然后更新,新增时主键还不存在,所以需手动设计

aop方式更新是针对修改和删除操作

  1. 手动设置示例
java 复制代码
stationService.addStationCacheUpdateStrategy(new StationCacheUpdateStrategyDTO(req.getId(),true));

具体执行的操作就是将数据设置到消息队列

java 复制代码
public void addStationCacheUpdateStrategy(StationCacheUpdateStrategyDTO dto) {
        try {
            rabbitTemplate.convertAndSend(RabbitConstant.BUSY_EXCHANGE, RabbitConstant.STATION_CACHE_INFO_UPDATE_QUEUE, dto);
        } catch (AmqpException e) {
//            throw new RuntimeException(e);
            log.error("站点缓存信息入队异常",e);
        }
    }
  1. aop方式设置
    定义注解
java 复制代码
package org.loulan.application.dragon.system.annotation;

import java.lang.annotation.*;
/**
 * 站点信息缓存注解
 * @ClassName StationCacheAnnotation
 * @Author yangfeng
 * @Date 2025/11/14 11:55
 * @Version 1.0
 */
@Target(ElementType.METHOD) // 注解只能用于方法
@Retention(RetentionPolicy.RUNTIME) // 注解在运行时保留
@Documented
public @interface StationCacheAnnotation {
    String value() default ""; // 可以定义属性,比如操作描述
    boolean isUpdated() default true;// 为true表示需要更新缓存(针对新增和更新场景)false表示删除缓存(针对删除场景)
    String parameterType() default "obj";//参数类型,默认为obj,表示传入的是StationCacheDTO对象;如果是id,表示传入的是站点ID
}

将需要处理的方法加上如上注解

定义切面

java 复制代码
package org.loulan.application.dragon.system.config;

import io.gitee.loulan_yxq.owner.core.bean.BeanTool;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.loulan.application.dragon.common.core.dto.StationCacheUpdateStrategyDTO;
import org.loulan.application.dragon.system.annotation.StationCacheAnnotation;
import org.loulan.application.dragon.system.service.DgStationService;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;

@Aspect
@Component
@Slf4j
public class StationCacheAnnotationAspect {
    @Resource
    private DgStationService stationService;

    @Pointcut("@annotation(org.loulan.application.dragon.system.annotation.StationCacheAnnotation)")
    public void methodsToProcess() {}

    // 定义切点:匹配所有被@StationCacheAnnotation注解的方法
    @AfterReturning(
            pointcut = "methodsToProcess()", // 引用上面定义的切点
            returning = "result" // 指定用于接收返回值的参数名
    )
    public Object afterAdvice(JoinPoint joinPoint, Object result) throws Throwable {
        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        // 获取注解
        StationCacheAnnotation annotation = method.getAnnotation(StationCacheAnnotation.class);
        String annotationValue = annotation.value();
        boolean updated = annotation.isUpdated();
        String type = annotation.parameterType();
        Object[] args = joinPoint.getArgs();
        // 在方法执行前可以做一些处理,比如日志记录
        log.info("开始执行方法: {} ,参数: {} ,注解值: {}", method.getName(),Arrays.toString(args), annotationValue);
        Integer stationId = -1;
        Object obj = null;
        if(type.equals("obj")){
            obj = args[0];
            Map<String, Object> paramMap = BeanTool.beanToMap(obj);
            Object o = paramMap.get("id");
            if(null==o){
                o = paramMap.get("stationId");
            }
            if(null!=o){
                stationId = (Integer) o;
            }
        }else {
            stationId = (Integer) args[0];
        }
        stationService.addStationCacheUpdateStrategy(new StationCacheUpdateStrategyDTO(stationId,updated));
        // 在方法执行后也可以做一些处理
        return result;
    }
}
  1. 消息消费,更新缓存
java 复制代码
    /**
     * 更新站点缓存信息
     * @param t
     * @param channel
     * @param deliveryTag
     * @Return: void
     * @author: yangfeng
     * @date: 2025/11/14 17:59
     **/
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = RabbitConstant.STATION_CACHE_INFO_UPDATE_QUEUE, durable = "true"),
            exchange = @Exchange(name = RabbitConstant.BUSY_EXCHANGE, durable = "false"),
            key = {RabbitConstant.STATION_CACHE_INFO_UPDATE_QUEUE}
    ))
    public void staCacheUpdate(StationCacheUpdateStrategyDTO t, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws IOException {
        log.info("需要更新的站点缓存信息为 msg = {}",t);
        String lockKey = RedisKey.STATION_CACHE_UPDATE_LOCK_KEY + t.getStationId();
        Boolean lock = distributedRedisLock.lock(lockKey,0,10, TimeUnit.SECONDS);
        if(lock){
            try {
                updateStaCache(t);
                channel.basicAck(deliveryTag,true);
            } catch (Exception e) {
                //出现异常直接丢弃消息,说明代码有问题
                channel.basicNack(deliveryTag, false, false);
                log.error("更新的站点缓存信息错误:{},数据:{}",e.getMessage(), t);
//                throw new RuntimeException(e);
            } finally {
                distributedRedisLock.unlock(lockKey);
            }
        }else{
            //requeue:true为将消息重返当前消息队列,还可以重新发送给消费者;false:将消息丢弃
            channel.basicNack(deliveryTag, false, false);
        }

    }

执行更新方法

java 复制代码
//更新单个气站缓存信息
    private void updateStaCache(StationCacheUpdateStrategyDTO t) {
        if(t.isUpdated()){
            StationDetailInfo detailInfo = bsStationLngService.getStationInfoDetailById(t.getStationId());
            if(ObjectTool.isNull(detailInfo)){
                log.warn("站点id={}的站点信息不存在,无法更新缓存",t.getStationId());
                return;
            }
            StationCacheDTO cacheDTO = BeanTool.copy(detailInfo, StationCacheDTO.class);
            if(ArrayTool.isNotEmpty(detailInfo.getCoord()) && detailInfo.getCoord().length==2){
                String[] coord = detailInfo.getCoord();
                cacheDTO.setLatitude(coord[0]);
                cacheDTO.setLongitude(coord[1]);
            }
            if(ObjectTool.isNotNull(detailInfo.getGradeTotal()) && ObjectTool.isNotNull(detailInfo.getGradeCount())){
                BigDecimal grade = detailInfo.getGradeTotal().divide(BigDecimal.valueOf(detailInfo.getGradeCount()), 1, RoundingMode.HALF_UP);
                cacheDTO.setGrade(grade.compareTo(new BigDecimal("3.6"))<0?new BigDecimal("3.6"):grade);
            }
            List<BsStaTags> staTags = detailInfo.getStaTags();
            if(CollTool.isNotEmpty(staTags)){
                List<Integer> tags = staTags.stream().map(BsStaTags::getTagId).toList();
                if(CollTool.isNotEmpty(tags)){
                    cacheDTO.setServerCodes(tags);
                }
            }else {
                cacheDTO.setServerCodes(new ArrayList<>());
            }
            StationCacheDTO redisData = (StationCacheDTO) redisTemplate.opsForHash().get(org.loulan.application.dragon.common.core.config.redis.RedisKey .STATION_HASH,detailInfo.getId()+"");
            if(ObjectTool.isNotNull(redisData)){
                BeanTool.copy(cacheDTO, redisData);
                redisTemplate.opsForHash().put(org.loulan.application.dragon.common.core.config.redis.RedisKey .STATION_HASH,detailInfo.getId()+"",redisData);
            }else{
                redisTemplate.opsForHash().put(org.loulan.application.dragon.common.core.config.redis.RedisKey .STATION_HASH,detailInfo.getId()+"",cacheDTO);
            }
        }else {
            //删除站点操作,直接伤处缓存
            redisTemplate.opsForHash().delete(org.loulan.application.dragon.common.core.config.redis.RedisKey .STATION_HASH,t.getStationId()+"");
        }
        

    }
相关推荐
a123560mh2 小时前
国产信创操作系统银河麒麟常见软件适配(MongoDB、 Redis、Nginx、Tomcat)
linux·redis·nginx·mongodb·tomcat·kylin
光泽雨2 小时前
python学习基础
开发语言·数据库·python
Elias不吃糖2 小时前
总结我的小项目里现在用到的Redis
c++·redis·学习
一个处女座的程序猿O(∩_∩)O3 小时前
Spring Boot、Redis、RabbitMQ 在项目中的核心作用详解
spring boot·redis·java-rabbitmq
让学习成为一种生活方式3 小时前
Pfam 数据库详解--生信工具60
数据库
q***49863 小时前
数据库操作与数据管理——Rust 与 SQLite 的集成
数据库·rust·sqlite
⑩-4 小时前
缓存穿透,击穿,雪崩
java·redis
川西胖墩墩4 小时前
流程图在算法设计中的实战应用
数据库·论文阅读·人工智能·职场和发展·流程图
clownAdam5 小时前
MongoDB-cdc原理
数据库·mongodb
最后1115 小时前
lamp-cloud 5.7.0 发布,新增缓存清理 + 修复优化全覆盖
java·后端·spring·缓存·springboot·springcloud