I have to implement Redis for cache management. I am following this
tutorial but the problem is when I use #Cacheable annotation on my controller method it gives me a 404 status code.
My Controller Method is as follows:
#GetMapping("auth/cache/{id}")
#Cacheable("test")
public ServiceResponse<String> checkingCache(#PathVariable("id") Integer id){
return new ServiceResponse<>(new String("String with id "+id));
}
When I remove the cacheable annotation the method works as expected.
I have installed redis on my machine and it is running on default port. Redis configuration is as follows:
spring.cache.type=redis
spring.redis.host=localhost
spring.redis.port=6379
Is there something I am missing? Any help would be much appreciated, Thanks!
have you enabled caching with annotation #EnableCaching described in your tutorial.
Also, because you need to cache for a specific id, you have to provide that key to che cache. Your example should be:
#GetMapping("auth/cache/{id}")
#Cacheable(value = "test", key = "#id")
public ServiceResponse<String> checkingCache(#PathVariable("id") Integer id){
return new ServiceResponse<>(new String("String with id "+id));
}
If you have no #PathVariable you can annotate #Cachable without a key
Related
#Cacheable(cacheNames = "BooksCache", key = "#id")
public Book findById(long id) {
LOGGER.info("Fetching Book From DB For BookId: {}", id);
return bookRepository.findById(id).orElse(null);
}
Cacheable is working fine but when we add a new book or update the existing book cache is not updating
Here is the code for saveOrUpdate() and I have used #CachePut to update the cache but that was not working, Database is getting updated but cache is not updating
#Transactional
#CachePut(cacheNames = "BooksCache", key = "#book.id")
public Book saveOrUpdateBook(Book book) {
return bookRepository.save(book);
}
I have tried #EnableTransactionManagement along with #Transactional Annotation.
I have also tried spring boot starter cache instead of redis cache,
But that was not working
You must call #Cachable- methods from another class. Otherwise the cache proxy will not work and the cache doesn't change/trigger.
#Cacheable #CacheEvict invalid
I has a service like this:
#service
pubic class TestService {
#Cacheable(cacheNames ="user",key = "#userId")
public User fetchUserById(Long userid) {
return new User();
}
public User fetchCurrentUser() {
return fetchUserById(124L);
}
}
there is some problem:
#Cacheable is valid, when I invoke fetchUserById(Long userid).
but #Cacheable is invalid, when I invoke fetchCurrentUser().
You can find solution here : Spring cache #Cacheable method ignored when called from within the same class
This is because of the way proxies are created for handling caching,
transaction related functionality in Spring. This is a very good
reference of how Spring handles it - Transactions, Caching and AOP:
understanding proxy usage in Spring
In short, a self call bypasses the dynamic proxy and any cross cutting
concern like caching, transaction etc which is part of the dynamic
proxies logic is also bypassed.
The fix is to use AspectJ compile time or load time weaving.
I found so many references about Spring Boot Caching.
I am able to implement at Repository method level.
#Cacheable(value = "booksByCategory", key = "#p0.categoryId", unless = "#result == null")
#EntityGraph(attributePaths = { "category" })
List<Book> findAllByCategoryId(Category category);
I would like cache the data at server startup instead of on first request.
How to do that ?
If you really want to "pre-load" your cache you could call findAllByCategoryId(category) for each expected category in a #PostConstruct method for the class that contains this method; e.g.:
#PostContstruct
void initCache() {
proxyRefToThisBean.findAllByCategoryId(cat1);
proxyRefToThisBean.findAllByCategoryId(cat2);
...
}
A method annotated with PostConstruct will be called during startup when your dependencies are being initialized.
My application has a monolithic application that is provided to spring Ehcache.It is worked correctly.It is important to know that the cache config is at service method and the lazy loading is true for all of object that is queried from DB.like this:
#Transactional
#Override
#Caching(evict = { #CacheEvict(value = "schoolCache", key = "#school.id")})
public Integer save(School school) {
// Code here
}
It is clear what is saved in the Ehcache is lazy instance of school.There is ModelMapper at controller layer to exchange data between Model and ViewModel like this:
#RequestMapping(value = "/load/{Id}", method = RequestMethod.GET)
#ResponseBody
public SchoolViewModel load(#PathVariable Integer Id) {
SchoolViewModel schoolViewModel = ModelMapper.map(schoolService.loadByEntityId(Id), SchoolViewModel.class);
return schoolViewModel;
}
If SchoolViewModel has an attribute of object that is into school is fetched from DB at controller by ModelMapper.
So i cluster the application and config Ehcache to Redis.
What is the problem? At the beginning when a request query from SchoolService,this service query from DB and because the session of hibernate has been opening,ModelMapper maps Model to ViewModel successfully.at the second time the service method that is called with id as same as id at first time get school object from Redis and there is not session of Hiberante,ModelMapper that want to map an attribute of an object that is into school gets exception.The exception is like this:
Caused by: org.hibernate.LazyInitializationException: could not
initialize proxy - no Session at
org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:165)
at
org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:286)
at
org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
So how do i do? What is the best way that helps me?
Thanks a lot
You need to initialize all associations that you further need in the service method:
schoolService.loadByEntityId(Id), SchoolViewModel.class)
So, you have multiple options:
You can use JOIN FETCH with a JPQL query.
You can use Hibernate.initialize(proxy) or Hibernate.unproxy(proxy).
You can simply navigate the LAZY associations.
You can use a DTO projection and you will never bump into any LazyInitializationException.
I have requirement for spring mvc 3 caching. Requirement is : while starting the server, we need to call database for one dropdown and put those values in the cache. So that whenever we required those values, we need to retrieve from cache.
Please help me with an example.
Thanks in advance.
May be you can use init-method (Spring 2.5) or #PostConstruct annotation (in Spring 3.0).
This method will be called during server start up
The following is code snippet
#Component
public class CacheDBData {
private String values[];
//add setter & getter
//This will be called during server start up after properties are initialised
#PostConstruct
public void getDataFromDB() {
values = //Logic to get data from DB and store that in values property
}
}
Suppose for example you can use in class as follows
#controller
public class HomeController {
#Autowired
private CacheDBData cacheDBData ;
//getter and setters
private void methodxyz() {
String values[] = cacheDBData.getValues();
}
}
I've had success with Ehcahe for Spring. There's a couple of config files to setup but after that you simply annotate the methods you want to cache the output from and it just works.
This has the advantage that you can change the values coming back from the service/database and NOT have to restart your app, unlike the accepted answer.