Wechat official account: if you have any questions or suggestions, please leave a message in the background, and I will try my best to solve your problems.

preface

As the question, today introduces SpringBoot data cache. Had developed all know is the bottleneck of application database, we also know that the speed of the memory is much faster than the hard disk, when need to be repeated for the same data, time and time again the request of the database or a remote service, lead to a lot of time spent on database query or remote method invocation, lead to the deterioration of performance, that is the problem of data cache.

Spring’s caching support

Spring defines org. Springframework. Cache. CacheManager and org., springframework. Cache. The cache interface for different caching technology. Among them, CacheManager is an abstract interface of various caching technologies provided by Spring, and the Cache interface contains various operations of the Cache (increase, delete, obtain the Cache, generally do not directly deal with this interface).

*1. CacheManager supported by Spring

Different CacheManager implementations are implemented for different caching technologies. Spring defines a CacheManager as shown in the following table:

CacheManager describe
SimpleCacheManager Use a simple Collection to store the cache, primarily for testing purposes
ConcurrentMapCacheManager Use ConcurrentMap to store the cache
NoOpCacheManager Only for test purposes, no actual caching of data
EhCacheCacheManager Use EhCache as the cache technology
GuavaCacheManager Use GuavaCache from Google Guava as the caching technology
HazelcastCacheManager Use Hazelcast as a caching technique
JCacheCacheManager Supports implementations of the JCache(JSR-107) standard as caching technologies, such as Apache ecommonsjCs
RedisCacheManager Use Redis as caching technology

To use any of the preceding CacheManager implementations, register the Implemented CacheManager beans, for example:

@Bean
public EhCacheCacheManager cacheManager(CacheManager ehCacheCacheManager){
    return new  EhCacheCacheManager(ehCacheCacheManager);
}
Copy the code

Note that each caching technology has many additional configurations, but configuring cacheManager is essential.

*2, * declaratively cache annotations

Spring provides four annotations to declare caching rules (another example of using annotated AOP). The four notes are as follows:

annotations explain
@Cacheable Spring checks whether there is any data in the cache before executing the method. If there is, it returns the cached data directly. If there is no data, the method is called and the method return value is put into the cache
@CachePut In any case, the return value of the method is put into the cache.
@CacheEvict Deletes one or more pieces of data from the cache
@Caching You can combine multiple annotation policies on a method with the @caching annotation

@cacheable, @cacheput, and @cacheevict all have a value attribute that specifies the cache name to use. The key attribute specifies the key that the data is stored in the cache.

*3. * Enable declarative caching support

Enabling declarative caching is as simple as using the @enablecaching annotation on the configuration class, for example:

@Configuration
@EnableCaching
public class AppConfig{}Copy the code

SpringBoot support

The key to using caching technology in Spring is to configure CacheManager, and SpringBoot provides us with multiple implementations of CacheManager.

It automatically configured in org. Springframework. Boot. Autoconfigure. The cache in the package.

In don’t do any configuration, the default is used SimpleCacheConfiguration, namely using ConcurrentMapCacheManager. SpringBoot supports configuring the cache with prefixes. Such as:

spring.cache.type= Optional: generic, ehcache, Hazelcast, Infinispan, jcache, Redis, Guava, Simple, None
spring.cache.cache-names= # Cache name created when the program starts
spring.cache.ehcache.config= # Ehcache configuration file address
spring.cache.hazelcast.config= # Hazelcast profile address
spring.cache.infinispan.config= # Infinispan configuration file address
spring.cache.jcache.config= # JCache configuration file address
spring.cache.jcache.provider= Specifies jCache implementations when multiple jCache implementations are in the classpath
# wait...
Copy the code

In the SpringBoot environment, the only way to use caching technology is to import the dependency packages of the caching technology into your project and EnableCaching support by using @enablecaching in your configuration class.

Code implementation

This paper will with SpringBoot default ConcurrentMapCacheManager as caching technology, demonstrate the @ Cacheable, @ CachePut, @ CacheEvict.

*1, * preparation

  • IDEA
  • JDK 1.8
  • SpringBoot 2.1.3

*2, * pom. XML file dependency

<?xml version="1.0" encoding="UTF-8"? >
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3. RELEASE</version>
        <relativePath/> <! -- lookup parent from repository -->
    </parent>
    <groupId>com.nasus</groupId>
    <artifactId>cache</artifactId>
    <version>0.0.1 - the SNAPSHOT</version>
    <name>cache</name>
    <description>cache Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <! -- cache dependency -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <! -- JPA dependency -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <! -- Web startup class -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <! Mysql > mysql > connect to database
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <! -- Lombok dependencies, simplifying entities -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <! -- Unit test class -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
Copy the code

The comments are clear and need not be said. You don’t just Google it.

*3, *Application. Yaml file configuration

spring:
  # Database related
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: JDBC: mysql: / / 127.0.0.1:3306 / test? useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=true
    username: root
    password: 123456
  # jpa related
  jpa:
    hibernate:
      ddl-auto: update   # dddl-auto: Set to create to create the table every time
    show-sql: true
Copy the code

*4, * entity class

package com.nasus.cache.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor
public class Student {

    @Id
    @GeneratedValue
    private Integer id;

    private String name;

    private Integer age;

}
Copy the code

* 5, * dao layer

package com.nasus.cache.repository;

import com.nasus.cache.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface StudentRepository extends JpaRepository<Student.Integer> {}Copy the code

* 6, * the service layer

package com.nasus.cache.service;

import com.nasus.cache.entity.Student;

public interface StudentService {

    public Student saveStudent(Student student);

    public void deleteStudentById(Integer id);

    public Student findStudentById(Integer id);

}
Copy the code

Implementation class:

package com.nasus.cache.service.impl;

import com.nasus.cache.entity.Student;
import com.nasus.cache.repository.StudentRepository;
import com.nasus.cache.service.StudentService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class StudentServiceImpl implements StudentService {

    // Use slf4J as the logging framework
    private static final Logger LOGGER = LoggerFactory.getLogger(StudentServiceImpl.class);

    @Autowired
    private StudentRepository studentRepository;

    @Override
    @CachePut(value = "student",key = "#student.id")
    // @cacheput Caches new or updated data to the cache, where the key for the cache name student data is the student ID
    public Student saveStudent(Student student) {
        Student s = studentRepository.save(student);
        LOGGER.info("Cache for data with id and key {}", s.getId());
        return s;
    }

    @Override
    @CacheEvict(value = "student")
    // @cacheevict removes data with key id from the cache student
    public void deleteStudentById(Integer id) {
        LOGGER.info(Delete data cache with id and key {}, id);
        //studentRepository.deleteById(id);
    }

    @Override
    @Cacheable(value = "student",key = "#id")
    // @cacheable Caches data with key id to student
    public Student findStudentById(Integer id) {
        Student s = studentRepository.findById(id).get();
        LOGGER.info("Cache for data with id and key {}", id);
        returns; }}Copy the code

Code explanation see the comment, very detailed.

7 *, *, the controller layer

package com.nasus.cache.controller;

import com.nasus.cache.entity.Student;
import com.nasus.cache.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.Mapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/student")
public class StudentController {

    @Autowired
    private StudentService studentService;

    @PostMapping("/put")
    public Student saveStudent(@RequestBody Student student){
        return studentService.saveStudent(student);
    }

    @DeleteMapping("/evit/{id}")
    public void deleteStudentById(@PathVariable("id") Integer id){
        studentService.deleteStudentById(id);
    }

    @GetMapping("/able/{id}")
    public Student findStudentById(@PathVariable("id") Integer id){
        returnstudentService.findStudentById(id); }}Copy the code

*8, *application Enables the cache function

package com.nasus.cache;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@EnableCaching // Enable cache
@SpringBootApplication
public class CacheApplication {

    public static void main(String[] args) { SpringApplication.run(CacheApplication.class, args); }}Copy the code

test

Before testing, take a look at the current database data, as follows:

*1, * test @cacheable

Visit http://localhost:8080/student/able/2 console to print out the SQL query, and specify the log. This time the program is directly query the database results.

The 22:54:54 2019-02-21. 1564-651 the INFO [nio - 8080 - exec - 1] O.S.W eb. Servlet. DispatcherServlet: Completed initializationin 11 ms
Hibernate: select student0_.id as id1_0_0_, student0_.age as age2_0_0_, student0_.name as name3_0_0_ from student student0_ wherestudent0_.id=? The 22:54:59 2019-02-21. 1564-725 the INFO [nio - 8080 - exec - 1] C.N.C.S ervice. Impl. StudentServiceImpl: for id, keys for 2 data cacheCopy the code

Results of Postman’s first test:

Visit http://localhost:8080/student/able/2 again the results below. However, the console does not print ANY SQL statements, nor does it cache the data whose ID and key are 2.

Note that @cacheable does cache data. The second test result was obtained from the data cache instead of directly looking up the database.

*2, * test @cachePut

The following figure, the postman to http://localhost:8080/student/put insert data:

Here is the console printing out the SQL Insert statement, as well as the specified log. Show that the program does caching.

Hibernate: insert into student (age, name, id) values (? ,? ,?) The 2019-02-21 23:12:03. 1564-688 the INFO [nio - 8080 - exec - 8] C.N.C.S ervice. Impl. StudentServiceImpl: for id, keys for 4 data cacheCopy the code

Insert data to return the result:

Results in the database:

Visit http://localhost:8080/student/able/4 Postman results below. The console has no output, which verifies that @cachePUT does cache, and the data in the figure below is fetched from the cache.

*3, * test @cacheevict

Postman visit http://localhost:8080/student/able/3 for id = 3 data cache.

Postman again to http://localhost:8080/student/able/3 to confirm the data retrieved from the cache.

Postman visit http://localhost:8080/student/evit/3

Delete data from cache with key 3:

Hibernate: select student0_.id as id1_0_0_, student0_.age as age2_0_0_, student0_.name as name3_0_0_ from student student0_ wherestudent0_.id=? The 2019-02-21 23:26:08. 8612-516 the INFO [nio - 8080 - exec - 2] C.N.C.S ervice. Impl. StudentServiceImpl: For id, keys for 3 data cache 2019-02-21 23:27:01. 8612-508 the INFO [nio - 8080 - exec - 4] C.N.C.S ervice. Impl. StudentServiceImpl: The data cache whose ID and key are 3 is deletedCopy the code

Visit http://localhost:8080/student/able/3 postman again observe the background, to do the data cache:

Hibernate: select student0_.id as id1_0_0_, student0_.age as age2_0_0_, student0_.name as name3_0_0_ from student student0_ wherestudent0_.id=? The 23:27:12 2019-02-21. 8612-320 the INFO [nio - 8080 - exec - 5] C.N.C.S ervice. Impl. StudentServiceImpl: for id, keys for 3 data cacheCopy the code

This set of tests proves that @Cacheevict does remove the data cache.

Download the source code

Github.com/turoDog/Dem…

Switching cache technology

The switching caching technique works in the same way as shown in the code above, except for adding the relevant dependency package configuration to the POM file.

Add Encache dependency to poM:

<! </groupId> </artifactId> </artifactId> </dependency>Copy the code

The Ehcache configuration file ehcache. XML needs only to be placed in the classpath (resource directory), SpringBoot will automatically scan, such as:

<? xml version="1.0" encoding="UTF-8">
<ehcache>
    <cache name="student" maxElementsInMmory="1000">
<ehcache>
Copy the code

SpringBoot automatically configures the EhcacheManager Bean.

*2, * switch to Guava

Simply add Guava dependencies to the POM:

<! </groupId> <artifactId> </artifactId> </artifactId> The < version > 18.0 < / version > < / dependency >Copy the code

SpringBoot automatically configures the GuavaCacheManager beans.

*3. * Switch to RedisCache

As with Guava, just add a dependency to the POM:

<! <groupId>org.springframework. Boot </groupId> <artifactId>spring-boot-starter-redis</artifactId> </dependency>Copy the code

SpringBoot automatically configures the Beans for RedisCacheManager and RedisTemplate.

In addition, the way other caching technologies are switched is similar. I won’t repeat it here.

After the language

This is the SpringBoot data cache tutorial.

If this article is of any help to you, please help.

Your good looks are what keeps me writing.

In addition, pay attention after sending 1024 can receive free learning materials. Python, C++, Java, Linux, Go, front-end, algorithm data sharing