面临 Spring Boot 的 @Cacheable 和 @CachePut 问题 - 缓存始终为空

问题描述 投票:0回答:1

我正在尝试构建一个简单的 Java SB 应用程序,该应用程序读取包含数据行的文本文件,例如:

{"id":"15887","customer_id":"528","load_amount":"$3318.47","time":"2000-01-01T00:00:00Z"}

我很难理解为什么我的缓存仍然为空,即使我显式调用 UpdateCacheService 中的方法(用 @Cacheable 或 @Cacheput 注释)。我已将与缓存交互的方法抽象到 UpdateCacheService 中,尽管我不确定我的各种注释和一般设置是否正确。

我尝试创建一个名为 UpdateCacheService 的服务,其中包含用 @Cacheable 和 @Cacheput 注释的各种方法。据我了解,@Cacheable 将根据提供的键检查缓存中是否有任何相应的值,如果找到某些内容,则此后的函数将不会被调用。 @Cacheput 则恰恰相反,其中调用函数,函数的返回值将作为提供的键的值以键:值对的形式存储在缓存中。我创建了一个服务来容纳我所有的各种缓存操作:

package com.example.fundloader.service;

import com.example.fundloader.model.DailyLoadInfo;
import com.example.fundloader.model.Load;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;

import static com.example.fundloader.constants.ApplicationConstants.DAILY_LOADS_CACHE;
import static com.example.fundloader.constants.ApplicationConstants.WEEKLY_LOADS_CACHE;

@Service
public class UpdateCacheService {
    @Cacheable(value = DAILY_LOADS_CACHE, key = "#load.customerId")
    public DailyLoadInfo loadCachedCustomerDailyData(Load load) {
        return null;
    }

    @Cacheable(value = WEEKLY_LOADS_CACHE, key = "#load.customer_id")
    public BigDecimal loadCachedCustomerWeeklyTotal(Load load) {
        return new BigDecimal(0);
    }

    @CachePut(value = DAILY_LOADS_CACHE, key = "#load.customerId")
    public DailyLoadInfo insertRecordIntoCache(DailyLoadInfo dailyCustomerLoadInfo) {

        return dailyCustomerLoadInfo;
    }

    @CachePut(value = WEEKLY_LOADS_CACHE, key = "#load.customerId")
    public BigDecimal updateWeeklyCache(BigDecimal total) {
        return total;
    }

    @CacheEvict(value = "#cacheName", allEntries = true)
    public void clearCache(String cacheName) {
    }
}

与另一个服务一起,其唯一目的是接受我正在读取的文本文件中的输入行,并调用 UpdateCacheService 和另一个 ValidateLoadService ,这实际上只是根据我施加的某些约束检查当前输入我自己(即,如果给定的 customer_id 在一天内存款超过 3 笔,则拒绝他们,或者如果他们每天存款超过 5,000 美元)。

缓存管理服务.java

import static com.example.fundloader.constants.ApplicationConstants.DAILY_LOADS_CACHE;
import static com.example.fundloader.constants.ApplicationConstants.WEEKLY_LOADS_CACHE;

@Service
public class CacheManagementService {
    private final CacheManager cacheManager;
    private final UpdateCacheService updateCacheService;
    private final ValidateLoadService validateLoadService;
    private Instant lastSeenDate;

    @Autowired
    public CacheManagementService(CacheManager cacheManager, UpdateCacheService updateCacheService, ValidateLoadService validateLoadService) {
        this.cacheManager = cacheManager;
        this.updateCacheService = updateCacheService;
        this.validateLoadService = validateLoadService;
    }


    public Boolean processLoad(Load load) {
        if (this.lastSeenDate != null) {
            syncCacheCalendar(this.lastSeenDate, load.getTransactionDate());
        }

        //Read value in from cache if available
        DailyLoadInfo dailyCustomerLoadInfo = this.updateCacheService.loadCachedCustomerDailyData(load);
        BigDecimal weeklyLoadAmount = this.updateCacheService.loadCachedCustomerWeeklyTotal(load);

        Boolean isValidInput = this.validateLoadService.isValidLoad(load, dailyCustomerLoadInfo, weeklyLoadAmount);
        if (isValidInput == null) {
            return null; // Duplicate load_id for unique user
        } else if (!isValidInput) {
            return false;
        }

        //TODO: Write to DB Service

        if (dailyCustomerLoadInfo == null) {
            dailyCustomerLoadInfo = assignCustomerLoad(load);
        } else {
            adjustDailyCustomerLoad(load, dailyCustomerLoadInfo);
        }

        boolean isDatabaseSuccess = true;

        if (isDatabaseSuccess) {
            this.lastSeenDate = this.updateCacheService.insertRecordIntoCache(dailyCustomerLoadInfo).getTransactionDate();
            this.updateCacheService.updateWeeklyCache(load.getLoadAmount().add(weeklyLoadAmount));
        }
        return true;
    }

在 CacheManagementService.java 中的 processLoad() 函数中,我调用

DailyLoadInfo dailyCustomerLoadInfo = this.updateCacheService.loadCachdCustomerDailyData(load);

我的期望是,在第一次命中时,这将是缓存未命中,因为缓存是空的。鉴于我的文本文件包含大量与 customer_id 相关的重复项,我知道在某些情况下我提供了一个键:值对,其中该键以前已经见过。话虽如此,我不知道为什么即使在处理超过 1000 行的文本文件后,我的缓存仍然为空。我尝试通过执行

cacheManager.get(<cacheName>).get(<key>)
直接访问缓存,但均无济于事(均返回null)。我只能假设我要么错误地设置了依赖项注入,要么我错过了和/或错过了某些重要位置的注释,例如@EnableCaching。

Main.java

package com.example.fundloader;

import com.example.fundloader.utils.FileIO;
import com.example.fundloader.model.Load;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@EnableCaching
@SpringBootApplication
public class FundLoaderApplication {

    private final FileIO<Load> loadsFileProcessor;

    @Autowired
    public FundLoaderApplication(FileIO<Load> loadsFileProcessor) {
        this.loadsFileProcessor = loadsFileProcessor;
    }

    public static void main(String[] args) {
        SpringApplication.run(FundLoaderApplication.class, args);
    }

    @PostConstruct
    public void processFiles() {
        loadsFileProcessor.processFile("src/main/resources/");
    }
}

CacheConfig.java

package com.example.fundloader.config;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import static com.example.fundloader.constants.ApplicationConstants.DAILY_LOADS_CACHE;
import static com.example.fundloader.constants.ApplicationConstants.WEEKLY_LOADS_CACHE;

@Configuration
@EnableCaching
public class LoadCacheConfig {

    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager(DAILY_LOADS_CACHE, WEEKLY_LOADS_CACHE);
    }
}

我非常感谢任何帮助,我已经被困了几天了,我不确定如何解决这个问题。

java spring-boot caching service
1个回答
0
投票

我不确定,因为我还没有看到完整的代码,但我认为这是因为第一次缓存始终为空,但这个值没有正确更新。

首先,由于loadCachedCustomerDailyData()的返回值为null,因此它将始终返回缓存的null值。 因此,processLoad方法中的dailyCustomerLoadInfo将以空值执行逻辑。

我不知道processLoad的isValidLoad()和assignCustomerLoad()是做什么的,但我预测逻辑不会按预期工作,因为第一次缓存总是为空。

尝试记录使用空值执行的每个条件和调试方法。希望这有帮助!

我已经评论了下面的代码。

@Service
public class UpdateCacheService {

    @Cacheable(value = DAILY_LOADS_CACHE, key = "#load.customerId")
    public DailyLoadInfo loadCachedCustomerDailyData(Load load) {
        // null value caching!
        return null;
    }

    @Cacheable(value = WEEKLY_LOADS_CACHE, key = "#load.customer_id")
    public BigDecimal loadCachedCustomerWeeklyTotal(Load load) {
        return new BigDecimal(0);
    }

    @CachePut(value = DAILY_LOADS_CACHE, key = "#load.customerId")
    public DailyLoadInfo insertRecordIntoCache(DailyLoadInfo dailyCustomerLoadInfo) {

        return dailyCustomerLoadInfo;
    }

    @CachePut(value = WEEKLY_LOADS_CACHE, key = "#load.customerId")
    public BigDecimal updateWeeklyCache(BigDecimal total) {
        return total;
    }

    @CacheEvict(value = "#cacheName", allEntries = true)
    public void clearCache(String cacheName) {
    }
}
public Boolean processLoad(Load load) {
        if (this.lastSeenDate != null) {
            syncCacheCalendar(this.lastSeenDate, load.getTransactionDate());
        }

        //Read value in from cache if available
        //First, cached null values!
        DailyLoadInfo dailyCustomerLoadInfo = this.updateCacheService.loadCachedCustomerDailyData(load);
        BigDecimal weeklyLoadAmount = this.updateCacheService.loadCachedCustomerWeeklyTotal(load);

        Boolean isValidInput = this.validateLoadService.isValidLoad(load, dailyCustomerLoadInfo, weeklyLoadAmount);
        if (isValidInput == null) {
            return null; // Duplicate load_id for unique user
        } else if (!isValidInput) {
            return false;
        }

        //TODO: Write to DB Service
        //It will always go into the null conditional branch below.
        if (dailyCustomerLoadInfo == null) {
            // I don't know assignCustomerLoad method...
            dailyCustomerLoadInfo = assignCustomerLoad(load);
        } else {
            adjustDailyCustomerLoad(load, dailyCustomerLoadInfo);
        }

        boolean isDatabaseSuccess = true;
                
        // It is expected that the logic below will not be called.
        if (isDatabaseSuccess) {
            this.lastSeenDate = this.updateCacheService.insertRecordIntoCache(dailyCustomerLoadInfo).getTransactionDate();
            this.updateCacheService.updateWeeklyCache(load.getLoadAmount().add(weeklyLoadAmount));
        }
        return true;
    }
© www.soinside.com 2019 - 2024. All rights reserved.