Spring Boot Redis Cache #CachePut is not updating the cache - spring

#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.

Related

spring data jpa: entity is still managed after transactional method completes

I am a beginner in spring boot and there is one thing that confuses me. As I understand it, in spring data jpa an EntityManger of type "container-managed transaction-scoped persistence context" is used. So according to my assumption, for each transactional service method a separate EntityManager should always be created to manage the entities within the method and after the method terminates all managed entities should be in detached state.
In the example below, StudentController calls 2 StudentService transactional methods. I thought that "studentService.insertStudent(studentEntity)" returns a detached entity and therefore "studentService.updateStudent(studentEntity1)" has no effect. But on the contrary, the entity is updated in DB, which means that it is still managed.
StudentController.java
#RequestMapping(
value = "/student",
method = {RequestMethod.PUT},
consumes = "application/json",
produces = "application/json"
)
public ResponseEntity<StudentEntity> insertStudent(#RequestBody StudentEntity studentEntity) {
StudentEntity studentEntity1 = studentService.insertStudent(studentEntity);
StudentEntity studentEntity2 = studentService.updateStudent(studentEntity1);
return new ResponseEntity<>(studentEntity2, HttpStatus.OK);
}
StudentService.java
#Transactional
public StudentEntity insertStudent(StudentEntity studentEntity){
return studentRepository.save(studentEntity);
}
#Transactional
public StudentEntity updateStudent(StudentEntity studentEntity){
studentEntity.setFirstName("firstName!!");
return studentEntity;
}
can someone please help me?

Configuring Spring transactions support for MongoDB

I am using spring-boot-starter-data-mongodb:2.2.1.RELEASE and trying to add transaction support for Mongo DB operations.
I have the account service below, where documents are inserted into two collections accounts and profiles. In case an error occurs while inserting into profile collection, the insertion into accounts should rollback. I have configured Spring transactions using MongoTransactionManager.
#Service
public class AccountService {
#Transactional
public void register(UserAccount userAccount) {
userAccount = accountRepository.save(userAccount);
UserProfile userProfile = new UserProfile(userAccountDoc.getId());
userProfile = profileRepository.save(userProfile);
}
}
Enabled Spring transaction support for MongoDB.
#Configuration
public abstract class MongoConfig extends AbstractMongoConfiguration {
#Bean
MongoTransactionManager transactionManager(MongoDbFactory dbFactory) {
return new MongoTransactionManager(dbFactory);
}
}
As per Spring reference doc https://docs.spring.io/spring-data/mongodb/docs/2.2.1.RELEASE/reference/html/#mongo.transactions that is all required to enable transactions for MongoDB. But this is not working. Insertions into accounts collection are not rolled back in case error occurs while inserting into profiles collection. Any suggestions if I am missing anything?
I would use command monitoring or examine query logs on the server side to ensure that:
session ids are sent with queries/write commands
transaction operations are performed (there is no startTransaction command but there is a commitTransaction)

Spring Boot Caching at server startup

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.

#Cacheable Annotation gives 404

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

#cacheput is not updating the existing cache

I am working with Spring 4 and Hazelcast 3.2. I am trying to add a new record to existing cache with below code. somehow cache is not getting updated and at the same time I don't see any errors also. below is the code snippet for reference.
Note:- Cacheable is working fine, only cacheput is not working. Please throw light on this
#SuppressWarnings("unchecked")`enter code here`
#Transactional(readOnly = true, propagation = Propagation.REQUIRED)
#Cacheable(value="user-role-data")
public List<User> getUsersList() {
// Business Logic
List<User> users= criteriaQuery.list();
}
#SuppressWarnings("unchecked")
#Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
#CachePut(value = "user-role-data")
public User addUser(User user) {
return user;
}
I had the same issue and managed to solved it. The issue seemed to be tied to the transaction management.
Bascially updating the cache in the same method where you are creating or updating the new record does not work because the transaction was not committed. Here's how I solved it.
Service layer calls repo to insert user
Then go back to service layer
After the insert /update db call
In the service layer I called a refresh cache method
That returned the user data and this method has the cacheput annotation
After that it worked.
An alternative approach is you could use #CacheEvict(allEntries = true) on the method used to Save or Update or Delete the records. It will flush the existing cache.
Example:
#CacheEvict(allEntries = true)
public void saveOrUpdate(Person person)
{
personRepository.save(person);
}
A new cache will be formed with updated result the next time you call a #Cacheable method
Example:
#Cacheable // caches the result of getAllPersons() method
public List<Person> getAllPersons()
{
return personRepository.findAll();
}

Resources