1

I am learning spring boot caching to apply this concept in our organization's project and I made a sample project called employe cache. I have four methods in my controller and service component insert, update, get, and getAll.For insert and get @Cacheable is working perfectly. Now I am calling getAllEmployee() first time then it is fetching data from the database. After that I am trying to update with @CachePut it updates the value in the database and again I am calling getAllEmployee() then it didn't return updated value from the cache. I also refer to the documentation for @CachePut. I also refer to some other documents like this and this but I didn't solve my problem. Also, When I am calling, no error is raised.
What I Tried is
These are my two APIs from EmplyeeController.java

@PostMapping(value = "/updateSalary")
private Boolean updateSalary(@RequestParam int salary, @RequestParam Integer id) {
    return empService.updateSalary(salary, id);
}

@GetMapping(value = "/getAllEmployee")
private Object getAllEmployee() {
    List<EmployeeMapping> empList = empService.getAllEmployee();
    return !empList.isEmpty() ? empList : "Something went wrong";
}

These are my two methods from EmployeeService.java. I applied different keys to update the method but didn't work. My getAll() method has no parameter so I tried all the keys techniques for no parameter methods from here then also I didn't get any results.

@CachePut(key = "#root.method.name")
public Boolean updateSalary(int salary, int id) {
    System.err.println("updateSalary method is calling in service");
    if (empRepo.salary(salary, id) != 0) {
        return true;
    }
    return false;
}

@Cacheable(key = "#root.method.name")
public List<EmployeeMapping> getAllEmployee() {
    return empRepo.findAllEmployee();
}

These are my two methods from EmployeeRepository.java. I used @SqlResultSetMappings and @NamedNativeQueriesin EmployeeMetaModel.java with EmployeeMapping.java but there is no error in native query in EmployeeMetaModel.java because it's giving result from database.

@Transactional
@Modifying
@Query("update employee_cache e set e.salary = ?1 where e.id = ?2")
int salary(int salary, int id);

@Query(name = "EmployeeListQuery", nativeQuery = true)
List<EmployeeMapping> findAllEmployee();

Kindly help me to get rid of this I just need an updated value from the cache using getAllEmployee() after updateSalary() called.

Deep Dalsania
  • 375
  • 3
  • 8
  • 22

1 Answers1

0

There is an issue with how you've defined caching via annotations. Your @CachePut and @Cacheable don't use the same cache key. What you should actually have is something like this:

@CachePut(value = "employees", key = "T(org.springframework.cache.interceptor.SimpleKey).EMPTY")
public List<EmployeeMapping> updateSalary(int salary, int id) {
    // update salary and return the list of employees
}

@Cacheable(value = "employees")
public List<EmployeeMapping> getAllEmployee() {
    // return the list of employees
}

Here @CachePutand @Cacheable have the same cache key.d Now, when you call the updateSalary() method, @CachePut will replace the existing cached value for key "employees", with the result of the method i.e. list of employees with updated salary.

Igor
  • 1,406
  • 2
  • 23
  • 45
  • Thanks for your valuable answer @Igor. I tried your solution but as per the rules we have to follow SPEL for key declaration so we have to add `#employees` not only `employees`. Otherwise, It will give `org.springframework.expression.spel.SpelEvaluationException` – Deep Dalsania May 10 '20 at 11:23
  • Also, I tried with `#employees` but it's not working and I try `@CacheConfig(cacheNames = "employee")` and `@CachePut(value = "employee", key = "#employees")` it's also not working. – Deep Dalsania May 10 '20 at 11:31
  • @DeepDalsania I've updated my answer. The SpEL expression for key in `@CachePut` should match the key value Spring uses to cache the result of `@Cacheable` annotated method (i.e. getAllEmployee) – Igor May 12 '20 at 20:21
  • I tried your updated answer @Igor. First I called `getAllEmployee()`. It gave the result by firing a query. Secon I called `updateSalary()`. It updates data firing a query. Third I again called `getAllEmployee()` and it gave exception that `java.lang.ClassCastException: java.lang.Boolean cannot be cast to java.util.List at com.spring.cache.service.EmployeeService$$EnhancerBySpringCGLIB$$90d3116e.getAllEmployee()` at where I called my service `getAllEmployee()` to controller. – Deep Dalsania May 13 '20 at 05:45
  • It appears that you have not updated `updateSalary`, and it still returns **Boolean**. The `updateSalary` should return same type of result as ` getAllEmployee` i.e. the **List** for `@CachePut` to work properly. This result is the value that `@CachePut` uses to replace existing value in cache. I case you do need boolean result from `updateSalary` method, then you'll have to update the cache within `updateSalary` using `org.springframework.cache.CacheManager` instead of `@CachePut` annotation. – Igor May 13 '20 at 08:13