I am using Spring Boot 1.5.9 on Tomcat 9.0.2 and I am trying to cache lookups using spring @Cacheable scheduling a cache refresh job that runs on application startup and repeats every 24 hours as follows:
@Component
public class RefreshCacheJob {
private static final Logger logger = LoggerFactory.getLogger(RefreshCacheJob.class);
@Autowired
private CacheService cacheService;
@Scheduled(fixedRate = 3600000 * 24, initialDelay = 0)
public void refreshCache() {
try {
cacheService.refreshAllCaches();
} catch (Exception e) {
logger.error("Exception in RefreshCacheJob", e);
}
}
}
and the cache service is as follows:
@Service
public class CacheService {
private static final Logger logger = LoggerFactory.getLogger(CacheService.class);
@Autowired
private CouponTypeRepository couponTypeRepository;
@CacheEvict(cacheNames = Constants.CACHE_NAME_COUPONS_TYPES, allEntries = true)
public void clearCouponsTypesCache() {}
public void refreshAllCaches() {
clearCouponsTypesCache();
List<CouponType> couponTypeList = couponTypeRepository.getCoupons();
logger.info("######### couponTypeList: " + couponTypeList.size());
}
}
the repository code:
public interface CouponTypeRepository extends JpaRepository<CouponType, BigInteger> {
@Query("from CouponType where active=true and expiryDate > CURRENT_DATE order by priority")
@Cacheable(cacheNames = Constants.CACHE_NAME_COUPONS_TYPES)
List<CouponType> getCoupons();
}
later in my webservice, when trying to get the lookup as follows:
@GET
@Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
@Path("/getCoupons")
@ApiOperation(value = "")
public ServiceResponse getCoupons(@HeaderParam("token") String token, @HeaderParam("lang") String lang) throws Exception {
try {
List<CouponType> couponsList = couponRepository.getCoupons();
logger.info("###### couponsList: " + couponsList.size());
return new ServiceResponse(ErrorCodeEnum.SUCCESS_CODE, resultList, errorCodeRepository, lang);
} catch (Exception e) {
logger.error("Exception in getCoupons webservice: ", e);
return new ServiceResponse(ErrorCodeEnum.SYSTEM_ERROR_CODE, errorCodeRepository, lang);
}
}
The first call it gets the lookup from the database and the subsequent calls it gets it from the cache, while it should get it from the cache in the first call in the web service?
Why am I having this behavior, and how can I fix it?
To enable the Spring Boot caching feature, you need to add the @EnableCaching annotation to any of your classes annotated with @Configuration or to the boot application class annotated with @SpringBootApplication .
Spring Cache uses the parameters of the method as key and the return value as a value in the cache. When the method is called the first time, Spring will check if the value with the given key is in the cache. It will not be the case, and the method itself will be executed.
While caching using reactive loading would be better than no caching at all, the best approach would be to proactively load the lookup table data into the cache at application startup. In this tutorial we will look at how to cache lookup table data and other static information.
Let’s begin! If you cannot find the startup apps in the Task Manager, then the first thing that you need to do is restart the Explorer application. Oftentimes, Windows programs get infected with temporary bugs and corruption errors, which prevents them from working properly.
The quick answer is to cache the current user in a global variable when the app starts. This can be done by setting the home screen’s OnStart property to this: Set (CurrentUser, User ()) Then anywhere in the app, just use CurrentUser just as you would User ()
Caching Data at Application Startup (C#) In any Web application some data will be frequently used and some data will be infrequently used. We can improve the performance of our ASP.NET application by loading in advance the frequently-used data, a technique known as Caching.
The issue was fixed after upgrading to Tomcat 9.0.4
While it's not affecting the scheduled task per se, when refreshAllCaches()
is invoked in the CacheService
, @CacheEvict
on clearCouponsTypesCache()
is bypassed since it's invoked from the same class (see this answer). It will lead to cache not being purged before
List<CouponType> couponTypeList = couponTypeRepository.getCoupons();
is invoked. This means that the @Cacheable
getCoupons()
method will not query the database, but will instead return values from the cache.
This makes the scheduled cache refresh action to do its work properly only once, when the cache is empty. After that it's useless.
The @CacheEvict
annotation should be moved to refreshAllCaches()
method and add beforeInvocation=true
parameter to it, so the cache is purged before being populated, not after.
Also, when using Spring 4 / Spring Boot 1.X, these bugs should be taken into consideration:
While this bug doesn't seem to affect this specific program, it might be a good idea to separate @Cacheable
annotation from JpaRepository
interface until migration to Spring 5 / Spring Boot 2.X.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With