@Cacheable and @CacheEvict Spring Boot

Mastering Spring Cache Annotations: A Guide to @Cacheable and @CacheEvict in Spring Boot

Caching is a very useful technique that can boost the performance of your Spring Boot applications by reducing the time taken to retrieve frequently accessed data. In this blog post, we’ll see how we can use Spring Cache annotations such as @Cacheable and @CacheEvict to manage cache eviction effectively. We’ll walk through the examples that will help you implement these annotations in your application and understand how to use them.

Mastering Spring Cache Annotations  A Guide to  Cacheable and CacheEvict in Spring Boot
@Cacheable and @CacheEvict Spring Boot


What is Caching?

Caching is the process of storing copies of files or data in a temporary storage area (called the cache) so that future requests for that data can be served much faster. In web applications, caching helps to reduce the load on the database and improves user response times, giving a better experience to the user.

Spring Cache Abstraction

Spring provides a caching abstraction that makes it easy to add caching to your applications. The Spring Cache abstraction is designed to support a wide variety of caching providers, including EhCache, Hazelcast, Caffeine, and more, so you can pick the caching provider that's right for you.

Getting Started with Spring Cache

To get started with caching in a Spring Boot application, you need to follow these steps:

  1. Add Dependencies: Ensure you have the necessary dependencies in your pom.xml or build.gradle file. For example, if you are using Maven, add the following dependency for Spring Boot Starter Cache:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
  1. Enable Caching: You need to enable caching in your Spring Boot application by adding the @EnableCaching annotation to your main application class.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@EnableCaching
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

Using @Cacheable

The @Cacheable annotation specifies that the return value of a method should be cached. Spring then checks to see if the result is already in the cache, and if so, returns the cached value. Otherwise, it executes the method, and stores the result in the cache for subsequent calls.

Example of @Cacheable

Let's create a simple service that retrieves user information from a database. We will cache the results of the getUser ById method.

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    // Simulating a database call
    public User getUser ById(Long id) {
        simulateSlowService(); // Simulate a slow service
        return new User(id, "User  " + id);
    }

    @Cacheable("users")
    public User getCachedUser ById(Long id) {
        return getUser ById(id);
    }

    // Simulate a slow service
    private void simulateSlowService() {
        try {
            Thread.sleep(3000); // Simulate delay
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
    }
}

In this example, the getCachedUserById method is annotated with the @Cacheable("users") annotation, so its results will be cached with the key "users". The first time you call this method with a given user ID, it takes 3 seconds to return the result. But any subsequent calls with the same user ID will return the cached result almost immediately, giving a significant performance boost.

Using @CacheEvict

The @CacheEvict annotation is used to remove entries from the cache. This is particularly useful when you want to invalidate the cache after an update or deletion operation.

Example of @CacheEvict

Let's extend our UserService to include a method for updating user information. We will use @CacheEvict to clear the cache when a user is updated.

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    // Existing methods...

    @CacheEvict(value = "users", key = "#user.id")
    public User updateUser  (User  user) {
        // Update user in the database (simulated)
        return user; // Return updated user
    }
}

In this example, the updateUser method is annotated with @CacheEvict(value = "users", key = "#user.id"). This means that when a user is updated, the corresponding entry in the cache will be removed, ensuring that the next call to getCachedUser ById will fetch the updated user information from the database.

Complete Example

Here’s how you can put everything together in a complete Spring Boot application.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/users")
@SpringBootApplication
@EnableCaching
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

    private final UserService userService;

    public MyApplication(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/{id}")
    public User getUser  (@PathVariable Long id) {
        return userService.getCachedUser  ById(id);
    }

    @PutMapping
    public User updateUser  (@RequestBody User user) {
        return userService.updateUser  (user);
    }
}

@Service
class UserService {

    public User getUser  ById(Long id) {
        simulateSlowService(); // Simulate a slow service
        return new User(id, "User   " + id);
    }

    @Cacheable("users")
    public User getCachedUser  ById(Long id) {
        return getUser  ById(id);
    }

    @CacheEvict(value = "users", key = "#user.id")
    public User updateUser  (User  user) {
        // Update user in the database (simulated)
        return user; // Return updated user
    }

    private void simulateSlowService() {
        try {
            Thread.sleep(3000); // Simulate delay
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
    }
}

class User {
    private Long id;
    private String name;

    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    // Getters and setters
}

Conclusion

In this blog post, we learned how to use the @Cacheable and @CacheEvict annotations in a Spring Boot application to manage caching. Using caching can significantly improve the performance of your application, especially for frequently accessed data. Be sure to choose the right caching provider for your application's needs and always test your caching strategy to ensure it meets your performance goals. Happy coding!

Post a Comment

Previous Post Next Post