项目实战中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()+"");
        }
        

    }
相关推荐
csdn_aspnet2 分钟前
用 MySQL 玩转数据可视化:从底层数据到 BI 工具的桥接
数据库·mysql·信息可视化·bi
wb043072017 分钟前
一次jvm配置问题导致的数据库连接异常
服务器·jvm·数据库·后端
酷酷的崽7988 分钟前
搭载cpolar,让PostgreSQL数据库远程访问超丝滑
数据库·postgresql
API开发15 分钟前
apiSQL 迁移至已有 PostgreSQL 数据库指南
数据库·postgresql·api开发·postgrest·接口开发工具·api管理软件
学掌门18 分钟前
从数据库到可视化性能,5个大数据分析工具测评,python只排倒数
数据库·python·数据分析
编程小风筝18 分钟前
Django REST framework实现安全鉴权机制
数据库·安全·django
secondyoung19 分钟前
队列原理与实现全解析
c语言·数据库·mysql·算法·队列
05大叔25 分钟前
微服务Day01 MP
数据库·oracle
Jan123.28 分钟前
深入理解数据库事务与锁机制:InnoDB实战指南
数据库·学习
wWYy.28 分钟前
详解redis(6):数据结构string、list
数据库·redis·缓存