This is the 9th day of my participation in the August More Text Challenge

preface

I know that in the interface API project, frequent call interface to get the data, querying the database is very expensive, so there will be a caching technology, can put some seldom update, or frequently used data, cache, and then the next request, directly from the cache access, don’t have to query data, so that we can provide program performance, Increase user experience, but also save the waste of service resources,

In Springboot to help you we do a good job of integration, there is a corresponding scene launcher start, we introduced between the use of good, help us integrate a variety of caches

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
    </dependencies>
Copy the code

Introduction to the

The cache is introduced

Spring has introduced Cache support since 3.1. Defines the org. Springframework. Cache. The cache and org., springframework. Cache. CacheManager unified interface to different caching technology. It also supports JCache (JSR-107) annotations to simplify our development.

Its usage and principles are similar to Spring’s support for transaction management. Spring Cache works on methods. The idea is that when we call a cached method, the method parameters and the return result are stored in the Cache as a key-value pair.

Describes the Cache and CacheManager interfaces

The Cache interface contains the set of operations on the Cache through which you operate the Cache. Spring provides various xxxCache implementations, such as RedisCache, EhCache, and ConcurrentMapCache

CacheManager defines how to create, configure, obtain, manage, and control multiple uniquely named caches. These caches exist in the context of CacheManager.

summary

Each time a method that requires caching is called, Spring checks to see if the specified target method with the specified parameter has already been called. If so, Spring fetches the result of the method call directly from the cache. If not, Spring calls the method and returns the result to the user. The next call is directly fetched from the cache.

There are two things to keep in mind when using the Spring cache abstraction;

  1. Determine the methods that need to be cached and their caching strategy
  2. Read from the cache data previously stored in the cache

Quick start

  1. Using caching We need to enable annotation-based caching using@EnableCachingNote on the SpringBoot main boot class or configuration class
@SpringBootApplication
@MapperScan(value = {"cn.soboys.kmall.mapper","cn.soboys.kmall.sys.mapper","cn.soboys.kmall.security.mapper"},nameGenerator = UniqueNameGenerator.class)
@ComponentScan(value = {"cn.soboys.kmall"},nameGenerator = UniqueNameGenerator.class)
@EnableCaching  // Enable the cache annotation driver, otherwise the caches used later will be invalid
public class WebApplication {
    private static ApplicationContext applicationContext;

    public static void main(String[] args) {
        applicationContext =
                SpringApplication.run(WebApplication.class, args);
        //displayAllBeans();
    }


    /** * prints all loaded beans */
    public static void displayAllBeans(a) {
        String[] allBeanNames = applicationContext.getBeanDefinitionNames();
        for(String beanName : allBeanNames) { System.out.println(beanName); }}}Copy the code

Or config classes

/ * * *@author kenx
 * @version 1.0
 * @date2021/8/17 sets *@webSitehttps://www.soboys.cn/ * Custom cache configuration */
@Configuration
@Slf4j
@EnableCaching  // Enable the cache annotation driver, otherwise the caches used later will be invalid
public class CacheConfig {

    // Customize the configuration class to configure keyGenerator

    @Bean("myKeyGenerator")
    public KeyGenerator keyGenerator(a){
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                return method.getName()+"["+ Arrays.asList(params).toString() +"]"; }}; }}Copy the code
  1. Annotation cache annotations are used where caching is required@Cacheableannotations
@CacheConfig(cacheNames = "menuCache",keyGenerator ="myKeyGenerator" )
public interface IMenuService extends IService<Menu> {
    /** * Get user menu information **@paramUsername username *@return* /
    @Cacheable(key = "#username")
    List<Menu> getUserMenus(String username);
}
Copy the code

The @cacheable annotation takes the following parameters to see the source code

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {
    @AliasFor("cacheNames")
    String[] value() default {};

    @AliasFor("value")
    String[] cacheNames() default {};

    String key(a) default "";

    String keyGenerator(a) default "";

    String cacheManager(a) default "";

    String cacheResolver(a) default "";

    String condition(a) default "";

    String unless(a) default "";

    boolean sync(a) default false;
}
Copy the code

Here are a few common attributes for @cacheable:

  1. CacheNames/Value: Specifies the name of the cache component. The cache in which to place the result of a method is an array. Multiple caches can be specified.

  2. Key: Specifies the key used to cache data. The default is to use the value of the method parameter. (This key you can write using spEL expressions like # I d; #a0 #p0 #root.args[0]

  3. KeyGenerator: a key generator; You can specify the component ID of the generator for key and then use either key or keyGenerator

  4. CacheManager: can be used to specify a cacheManager. Which cache manager to fetch the cache from. Or cacheResolver specifies to get the parser

  5. Condition: Can be used to specify conditions to cache

Condition = "#id>0" condition = "#a0>1"Copy the code
  1. Unless: Deny cache. When the condition specified by unless is true, the return value of the method is not cached. Of course, you can also get the results to judge. (Use #result to get method results)
Unless = "#result == null" unless = "#a0==2": If the value of the first parameter is 2, the result is not cached;Copy the code
  1. Sync: indicates whether to use asynchronous mode. In asynchronous modeunlessThe default value is after the method is executed, the result returned by the method is stored in the cache synchronously

CacheNames/the value attribute

It is used to specify the name of the cache component and the cache in which the result of the method should be placed. It can be an array. Multiple caches are supported

 /** * Get user menu information **@paramUsername username *@return* /
    @Cacheable(cacheNames = "menuCache")or// @Cacheable(cacheNames = {"menuCache","neCacge"})
    List<Menu> getUserMenus(String username);
Copy the code

If there is only one property, cacheNames can be ignored and the value property is the default

key

The key used to cache data. By default, the values of the method parameters are used. You can write it using spEL expressions.

Cache SpEL available metadata

The name of the location describe The sample
methodName The root object The name of the method currently being called #root.methodname
method The root object The method currently being called #root.method.name
target The root object The target object instance that is currently being invoked #root.target
targetClass The root object The class of the target object currently being called #root.targetClass
args The root object A list of arguments to the currently invoked method #root.args[0]
caches The root object List of caches used by the current method call #root.caches[0].name
argumentName Avaluation Context The parameters of the currently invoked method, such as findArtisan(Artisan Artisan), can be obtained with # artsia.id #artsian.id
result Evaluation Context Return value after method invocation (only if the determination after method invocation is valid, such as unless cacheEvict’s beforeInvocation=false) #result
//key = "#username
 @Cacheable(key = "#username" ,cacheNames = "menuCache")
List<Menu> getUserMenus(String username);
Copy the code

keyGenerator

The key generator, which you can specify yourself, is used to generate the key

Define an @Bean class to add KeyGenerator to the Spring container

@Configuration
@Slf4j
@EnableCaching  // Enable the cache annotation driver, otherwise the caches used later will be invalid
public class CacheConfig {

    // Customize the configuration class to configure keyGenerator

    @Bean("myKeyGenerator")
    public KeyGenerator keyGenerator(a){
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                return method.getName()+"["+ Arrays.asList(params).toString() +"]"; }}; }}Copy the code

When specifying your own @cacheable (cacheNames =” menuCache”,keyGenerator =”myKeyGenerator”)

Note that the generation rules for keys placed in the cache will follow your own custom keyGenerator. Note, however, that the @cacheable attribute can be used with either key or keyGenerator.

condition

Cache only if conditions are met. You can make a dynamic decision whether to cache the data returned by a method.

 /** * Get user menu information **@paramUsername username *@return* /
    // Verify that the username starts with kenx
    @Cacheable(key = "#username" ,condition = "#username.startsWith('kenx')")
    List<Menu> getUserMenus(String username);
Copy the code

unless

Deny caching. When the condition specified by unless is true, the return value of the method is not cached.

 /** * Get user menu information **@paramUsername username *@return* /
    // Check whether the username starts with kenx
    @Cacheable(key = "#username" ,condition = "#username.startsWith('kenx')")
    List<Menu> getUserMenus(String username);
Copy the code

SpEL write key

The cacheNames keyGenerator property can be used with the @Cacheconfig annotation to extract the cache’s common configuration and then add it to the class, eg: for example

// Use the cache method instead of the global configuration
@CacheConfig(cacheNames = "menuCache",keyGenerator ="myKeyGenerator" )
public interface IMenuService extends IService<Menu> {
    /** * Get user menu information **@paramUsername username *@return* /
    @Cacheabl
    List<Menu> getUserMenus(String username);
}

Copy the code

Further use

@CachePut

The @cacheput annotation is also used for caching. However, caching differs from @cacheable in that it calls a method and then updates the cache. That is, a method operation is performed and the cache is updated synchronously. The primary key attribute has a lot in common with @cacheable see the @cacheput source code

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CachePut {
    @AliasFor("cacheNames")
    String[] value() default {};

    @AliasFor("value")
    String[] cacheNames() default {};

    String key(a) default "";

    String keyGenerator(a) default "";

    String cacheManager(a) default "";

    String cacheResolver(a) default "";

    String condition(a) default "";

    String unless(a) default "";
}
Copy the code
/ * * *@CachePut: calls methods and updates cached data; Synchronous update cache * modifies data while updating the cache */
    @CachePut(value = {"emp"}, key = "#result.id")
    public Employee updateEmp(Employee employee){
        employeeMapper.updateEmp(employee);
        LOG.info("Update employee data {}",employee.getId());
        return employee;
    }
Copy the code

@CacheEvict

Clear the cache main attributes:

  1. Key: specifies the data to be cleared
  2. AllEntries = true: Specifies that all data in the cache should be erased
  3. BeforeInvocation = false: The default means that the cache cleanup is performed after the method executes
  4. BeforeInvocation = true: Indicates that the clear cache operation is performed before the method runs
@CacheEvict(value = {"emp"}, beforeInvocation = true,key="#id")
    public void deleteEmp(Integer id){
        employeeMapper.deleteEmpById(id);
        //int i = 10/0;
    }
Copy the code

@Caching

@Caching is used to define complex Caching rules, which can be integrated with @cacheable and @cachePUT

// @caching Defines complex Caching rules
    @Caching( cacheable = { @Cacheable(/*value={"emp"},*/key = "#lastName") }, put = { @CachePut(/*value={"emp"},*/key = "#result.id"), @CachePut(/*value={"emp"},*/key = "#result.email") } )
    public Employee getEmpByLastName(String lastName){
        return employeeMapper.getEmpByLastName(lastName);
    }

Copy the code

@CacheConfig

The @Cacheconfig annotation can be used to extract the common configuration of the cache and then add it to the class

// Use the cache method instead of the global configuration
@CacheConfig(cacheNames = "menuCache",keyGenerator ="myKeyGenerator" )
public interface IMenuService extends IService<Menu> {
    /** * Get user menu information **@paramUsername username *@return* /
    @Cacheable(key = "#username" )
    List<Menu> getUserMenus(String username);
}
Copy the code

reference

  1. SpringBoot cache tutorial
  2. The cache entry