我正在尝试构建一个简单的 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);
}
}
我非常感谢任何帮助,我已经被困了几天了,我不确定如何解决这个问题。
我不确定,因为我还没有看到完整的代码,但我认为这是因为第一次缓存始终为空,但这个值没有正确更新。
首先,由于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;
}