SpringBoot Combat (11) | Интеграция кеша данных

Spring Boot

Публичный аккаунт WeChat: отличная трата времени Если у вас есть какие-либо вопросы или предложения, оставьте сообщение в фоновом режиме, и я сделаю все возможное, чтобы решить вашу проблему.

предисловие

Если это, сегодня введен тайнобот в кеш данных. Знал, что разработка программы состоит в том, что узкое место базы данных, мы также знаем, что скорость памяти намного быстрее, чем жесткий диск, когда вам нужно получить те же данные, повторяющиеся, снова и снова, или запросить службы удаленной базы данных, В результате много времени, потраченного на запросы к базе данных или на вызове удаленного метода, что приведет к ухудшению производительности, что является кэшем данных для решения проблемы.

Поддержка кэширования Spring

Spring определяет интерфейсы org.springframework.cache.CacheManager и org.springframework.cache.Cache для унификации различных технологий кэширования. Среди них CacheManager — это абстрактный интерфейс различных технологий кэширования, предоставляемых Spring, а интерфейс Cache включает в себя различные операции кэширования (добавление, удаление и получение кеша, как правило, напрямую не связанные с этим интерфейсом).

* 1, * Spring поддерживает CacheManager

Для разных технологий кэширования реализованы разные CacheManagers. Spring определяет CacheManagers, показанные в следующей таблице:

CacheManager описывать
SimpleCacheManager Используйте простую коллекцию для хранения кеша, в основном для тестирования
ConcurrentMapCacheManager CONDURRENTMAP Используйте кэш для хранения
NoOpCacheManager Только в целях тестирования, никакие данные не будут кэшироваться.
EhCacheCacheManager Использование EhCache в качестве технологии кэширования
GuavaCacheManager Использование Google Guava GuavaCache в качестве технологии кэширования
HazelcastCacheManager Использование Hazelcast в качестве технологии кэширования
JCacheCacheManager Реализация, поддерживающая стандарт JCache (JSR-107) в качестве технологии кэширования, например ApacheCommonsJCS.
RedisCacheManager Используйте Redis в качестве технологии кэша

При использовании любого из CacheManager, реализованного выше, вам необходимо зарегистрировать bean-компонент, который реализовал CacheManager, например:

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

Обратите внимание, что каждая технология кэширования имеет множество дополнительных настроек, но настройка cacheManager необходима.

*2, *Аннотации декларативного кэша

Spring предоставляет 4 аннотации для объявления правил кэширования (опять же, пример использования Annotated AOP). 4 аннотации следующие:

аннотация объяснять
@Cacheable В методе Spring сначала просмотрите кеш в кеше, если есть, верните данные кеша напрямую, если данных нет, метод вызова вернет метод в кеш.
@CachePut В любом случае, возвращаемое значение метода помещается в кэш.
@CacheEvict Удалить один или несколько фрагментов данных из кеша
@Caching Несколько стратегий аннотаций можно комбинировать в методе с помощью аннотации @Caching.

@Cachable, @Cacheput, и @Cacheeevict все имеют атрибут Value, который указывает имя кэша для использования; атрибут ключа указывает клавишу для хранения данных в кэше.

*3, *Включить поддержку декларативного кэша

Включить декларативное кэширование легко, просто используйте аннотацию @EnableCaching в классе конфигурации, например:

@Configuration
@EnableCaching
public class AppConfig{

}

Поддержка Springboot

Ключом к использованию технологии кэширования в Spring является настройка CacheManager, а SpringBoot настраивает для нас несколько реализаций CacheManager.

Его автоконфигурация размещена в пакете org.springframework.boot.autoconfigure.cache.

Без какой-либо настройки по умолчанию используется SimpleCacheConfiguration, то есть используется ConcurrentMapCacheManager. SpringBoot поддерживает настройку кешей с префиксами. Например:

spring.cache.type= # 可选 generic、ehcache、hazelcast、infinispan、jcache、redis、guava、simple、none
spring.cache.cache-names= # 程序启动时创建的缓存名称
spring.cache.ehcache.config= # ehcache 配置文件的地址
spring.cache.hazelcast.config= # hazelcast配置文件的地址
spring.cache.infinispan.config= # infinispan配置文件的地址
spring.cache.jcache.config= # jcache配置文件的地址
spring.cache.jcache.provider= # 当多个 jcache 实现在类路径的时候,指定 jcache 实现
# 等等。。。

В среде SpringBoot для использования технологии кэширования нужно только импортировать зависимости соответствующей технологии кэширования в проект и использовать @EnableCaching в классе конфигурации, чтобы включить поддержку кэширования.

Код

Эта статья будет использовать SpringBoot по умолчанию ConcurrentMapcachemanager в качестве технологии кэширования, чтобы продемонстрировать @cachable, @Cacheput и @Cacheevict.

*1, *Подготовка

  • IDEA
  • JDK 1.8
  • SpringBoot 2.1.3

*2, *Зависимость файла Pom.xml

<?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-SNAPSHOT</version>
    <name>cache</name>
    <description>cache Demo project for Spring Boot</description>

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

    <dependencies>
        <!-- cache 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <!-- JPA 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- web 启动类 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- mysql 数据库连接类 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- lombok 依赖,简化实体 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- 单元测试类 -->
        <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>

Комментарии ясны и не нужны. Не просто гуглите.

*3, *Конфигурация файла Application.yaml

spring:
  # 数据库相关
  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 相关
  jpa:
    hibernate:
      ddl-auto: update   # ddl-auto: 设为 create 表示每次都重新建表
    show-sql: true

* 4, * класс сущности

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;

}

*5, *дао слой

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> {
}

*6, *сервисный уровень

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);

}

Класс реализации:

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 {

    // 使用 slf4j 作为日志框架
    private static final Logger LOGGER = LoggerFactory.getLogger(StudentServiceImpl.class);

    @Autowired
    private StudentRepository studentRepository;

    @Override
    @CachePut(value = "student",key = "#student.id")
    // @CachePut 缓存新增的或更新的数据到缓存,其中缓存名称为 student 数据的 key 是 student 的 id
    public Student saveStudent(Student student) {
        Student s = studentRepository.save(student);
        LOGGER.info("为id、key 为{}的数据做了缓存", s.getId());
        return s;
    }

    @Override
    @CacheEvict(value = "student")
    // @CacheEvict 从缓存 student 中删除 key 为 id 的数据
    public void deleteStudentById(Integer id) {
        LOGGER.info("删除了id、key 为{}的数据缓存", id);
        //studentRepository.deleteById(id);
    }

    @Override
    @Cacheable(value = "student",key = "#id")
    // @Cacheable 缓存 key 为 id 的数据到缓存 student 中
    public Student findStudentById(Integer id) {
        Student s = studentRepository.findById(id).get();
        LOGGER.info("为id、key 为{}的数据做了缓存", id);
        return  s;
    }
}

Код объясняет комментарий, очень подробный.

*7, *уровень контроллера

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){
        return studentService.findStudentById(id);
    }

}

*8, *приложение включает функцию кэширования

package com.nasus.cache;

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

@EnableCaching // 开启缓存功能
@SpringBootApplication
public class CacheApplication {

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

контрольная работа

Перед тестированием взгляните на текущие данные в базе данных следующим образом:

原始数据库数据

*1, *Тест @Cacheable

доступhttp://localhost:8080/student/able/2Консоль распечатает оператор SQL Query и указанный журнал. Объясните, что на этот раз программа является результатом, полученным непосредственно запрашивая базу данных.

2019-02-21 22:54:54.651  INFO 1564 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 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_ where student0_.id=?
2019-02-21 22:54:59.725  INFO 1564 --- [nio-8080-exec-1] c.n.c.service.impl.StudentServiceImpl    : 为id、key 为2的数据做了缓存

Результаты первого теста почтальона:

postman 第一次测试结果

посетить сноваhttp://localhost:8080/student/able/2Результат показан ниже. Но в консоли нет инструкции SQL, ниКэшированные данные с идентификатором и ключом 2Это предложение вывода.

Описание @CacHeable создает кеш данных, второй результат теста получается из кеша данных и прямой базы данных нет.

postman 第二次测试结果

*2, *Тест @CachePut

Как показано ниже, Postman Accesshttp://localhost:8080/student/putВставить данные:

postman 测试 @CachePut

Ниже консоль распечатывает оператор вставки SQL и указанный журнал. Указывает, что программа находится в кэше.

Hibernate: insert into student (age, name, id) values (?, ?, ?)
2019-02-21 23:12:03.688  INFO 1564 --- [nio-8080-exec-8] c.n.c.service.impl.StudentServiceImpl    : 为id、key 为4的数据做了缓存

Результат, возвращаемый вставкой данных:

postman 第一次测试结果

Результат в базе:

新增的数据

доступhttp://localhost:8080/student/able/4Результаты почтальона показаны ниже. Консоль не имеет вывода и проверяет, что @CacHeput действительно создает кеш, и из кеша получаются следующие данные.

@Cacheable 测试结果

*3, *Тест @CacheEvict

визит почтальонаhttp://localhost:8080/student/able/3Кэшируйте данные с ID = 3.

почтальон снова в гостяхhttp://localhost:8080/student/able/3Подтвердите, что данные получены из кеша.

визит почтальонаhttp://localhost:8080/student/evit/3

postman 访问 http://localhost:8080/student/evit/3

Удалить закэшированные данные с ключом 3 из кеша:

Hibernate: select student0_.id as id1_0_0_, student0_.age as age2_0_0_, student0_.name as name3_0_0_ from student student0_ where student0_.id=?
2019-02-21 23:26:08.516  INFO 8612 --- [nio-8080-exec-2] c.n.c.service.impl.StudentServiceImpl    : 为id、key 为3的数据做了缓存
2019-02-21 23:27:01.508  INFO 8612 --- [nio-8080-exec-4] c.n.c.service.impl.StudentServiceImpl    : 删除了id、key 为3的数据缓存

почтальон снова в гостяхhttp://localhost:8080/student/able/3Наблюдайте за фоном и переделайте кеш данных:

Hibernate: select student0_.id as id1_0_0_, student0_.age as age2_0_0_, student0_.name as name3_0_0_ from student student0_ where student0_.id=?
2019-02-21 23:27:12.320  INFO 8612 --- [nio-8080-exec-5] c.n.c.service.impl.StudentServiceImpl    : 为id、key 为3的数据做了缓存

Этот набор тестовых процедур доказывает, что @CacheEvict действительно удаляет кеш данных.

Загрузка исходного кода

GitHub.com/FigureROdog/DEM…

Технология кэширования коммутатора

Технология Cache переключения используется так же, как и вышеуказанная демонстрация кода, за исключением того, что в файл POM добавляется соответствующая конфигурация пакета зависимости.

*1, *Переключить EhCache Добавьте зависимость Encache к pom:

<!-- EhCache 依赖 -->
<dependency>
     <groupId>net.sf.ehcache</groupId>
     <artifactId>ehcache</artifactId>
</dependency>

Файл конфигурации ehcache.xml, требуемый Ehcache, нужно только поместить в путь к классам (каталог ресурсов), и SpringBoot автоматически просканирует, например:

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

SpringBoot автоматически настроит bean-компонент EhcacheManager.

*2, *Переключить гуаву

Просто добавьте зависимость Guava к вашему pom:

<!-- GuavaCache 依赖 -->
<dependency>
     <groupId>com.google.guava</groupId>
     <artifactId>guava</artifactId>
     <version>18.0</version>
</dependency>

SpringBoot автоматически настроит bean-компонент GuavaCacheManager.

*3, *Переключение RedisCache

Как и в случае с Guava, просто добавьте зависимость в pom:

<!-- cache 依赖 -->
<dependency>         
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-redis</artifactId>
</dependency>

SpringBoot автоматически настроит bean-компоненты RedisCacheManager и RedisTemplate.

Кроме того, переключение на другие методы кэширования аналогичны. Еще не разработано здесь.

послесловие

Учебник для кэша данных Scraphboot.

Если эта статья поможет вам хоть немного, пожалуйста, помогите.

Ваша привлекательная внешность мотивирует меня продолжать писать.

Кроме того, я отправляю его после того, как обратил внимание1024Вы можете получить бесплатные учебные материалы. Подробности информационного содержания см. в этой старой статье:Python, C++, Java, Linux, Go, интерфейс, алгоритмы, обмен данными

一个优秀的废人