目录
缓存
项目总结
新建一个SpringBoot项目
pom.xml
application.properties
CacheConfig
Book
BookRepository接口
BookService服务类
BookController控制器
SpringbootCacheApplication启动类
启动项目,使用Postman测试
参考博文:
- 1、使用到了JPA,建议先看看SpringBoot整合JPA保存数据:http://t.csdnimg.cn/zJfHv
缓存
Spring Boot 实际上是建立在 Spring Framework 的基础之上的,并且提供了对 Spring Framework 中各种功能的自动化配置和简化,包括缓存抽象。
Spring Framework 提供了一套强大的缓存抽象,包括
@Cacheable
、@CachePut
、@CacheEvict
等注解,以及CacheManager
接口和相关的实现类,用于管理缓存的操作和配置。这些缓存抽象使得开发人员可以方便地在应用程序中集成各种缓存解决方案,并使用统一的方式来进行缓存操作。- 缓存机制:Spring的缓存抽象是作用于方法级别的,在每次调用一个目标方法时,缓存抽象都会应用一个缓存行为来检查是否已经为给定参数调用了该方法。如果已经调用该方法,则返回缓存的结果,而不会再调用实际的方法;如果还没有调用该方法,则会调用目标方法,并将方法返回的结果缓存,同时向用户返回该结果。这种缓存机制适用于对给定参数始终返回相同结果的方法
- 缓存抽象提供了5个缓存注解:
@Cacheable 根据方法参数将方法结果保存到缓存中 @CachePut 执行方法,同时更新缓存 @CacheEvict 清空缓存 @Caching 重新组合要应用于某个方法的多个缓存操作 @CacheConfig 在类级别共享一些共同的缓存相关配置
项目总结
- 引入依赖
- 在
application.properties
或application.yml
中配置数据库连接,所选缓存提供商的相关信息- 在 Spring Boot 应用程序的主类上,添加
@EnableCaching
注解来启用缓存支持- 在需要进行缓存的方法上添加
@Cacheable
、@CachePut
、@CacheEvict
等注解,来控制缓存的行为。
新建一个SpringBoot项目
引入依赖:
- Lombok
- Spring Web
- Spring Data JPA
- MySQL Driver
- Spring Cache Abstraction
项目结构:
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 https://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.3.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.study</groupId>
<artifactId>springboot_cache</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot_cache</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.32</version>
<scope>runtime</scope>
</dependency>
<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>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.properties
# test为数据库名
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=true
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# Hibernate配置属性,设置自动根据实体类创建,更新和验证数据库表结构
spring.jpa.properties.hibernate.hbm2ddl.auto=update
# Hibernate 将会使用 MySQL 5 InnoDB 存储引擎的方言来生成针对 MySQL 数据库的 SQL 查询和语句。
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
# 将运行期生成的SQL语句输出到日志以供调试
spring.jpa.show-sql=true
CacheConfig
- 因为缓存本质上是键-值存储,所以每次调用缓存的方法都需要转换成合适的键来进行缓存访问。
- 默认的键生成策略:
- 如果缓存方法没有参数,则使用SimpleKey.EMPTY作为键
- 如果有多个参数,则返回包含所有参数的SimpleKey
package com.study.springboot_cache.config;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* 这是一个自定义的缓存键生成器(KeyGenerator)配置类。
* 在这个配置类中,你重写了 CachingConfigurerSupport 类的 keyGenerator() 方法,
* 用于生成缓存的键,避免出现重复的键。
*/
@Configuration
public class CacheConfig extends CachingConfigurerSupport {
@Bean
@Override //alt+insert
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
/**
* 将目标对象的类名、方法名和参数数组拼接起来作为键的生成规则,以确保缓存的唯一性
*/
@Override
public Object generate(Object target, Method method, Object... objects) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName())
.append(".")
.append(method.getName())
.append(Arrays.toString(objects));
return sb.toString();
}
};
}
}
Book
package com.study.springboot_cache.entity;
import lombok.Data;
import lombok.ToString;
import javax.persistence.*;
import java.time.LocalDate;
@Data
@ToString
@Entity
@Table(name = "books")
public class Book {
//主键自动增长
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;//主键ID
private String title;//书名
private String author;//作者
private String bookConcern;//出版社
private LocalDate publishDate;//出版日期
private Float price;//价格
}
BookRepository接口
- JpaRepository 接口:是 Spring Data JPA 提供的一个泛型接口,用于简化数据访问层的开发。它提供了许多内置的方法,用于对实体类进行常见的 CRUD 操作
package com.study.springboot_cache.repository;
import com.study.springboot_cache.entity.Book;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BookRepository extends JpaRepository<Book,Integer> {
Book getById(Integer id);
}
BookService服务类
- 对于DAO类来说,通常是一个方法完成一次SQL访问操作,粒度比较细,对于一次前端请求来说,可能需要调用多个DAO类方法来得到结果,而服务层就是负责组合这些DAO方法的,因此,在服务层的类方法缓存结果是比较合适的
- SpEL(Spring Expression Language,Spring表达式语言),可以通过SpEL来选择合适的参数生成键
package com.study.springboot_cache.service;
import com.study.springboot_cache.entity.Book;
import com.study.springboot_cache.repository.BookRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
/**
* @CacheConfig(cacheNames = "book")在类级别共享一些共同的缓存相关配置
* 设置缓存的名称为book
*/
@Service
@CacheConfig(cacheNames = "book")
public class BookService {
@Autowired
private BookRepository bookRepository;
/**
* @Cacheable根据方法参数将方法结果保存到缓存中,在后续使用相同参数调用方法时,
* 会直接返回缓存中的值,而不再调用目标方法
*/
@Cacheable
public Book getBookById(Integer id){
System.out.println("getBookById: "+id);
return bookRepository.getById(id);
}
/**
* @CachePut(key = "#result.id")调用方法以更新缓存
* key = "#result.id": 缓存的key,其值为SpEL表达式
*/
@CachePut(key = "#result.id")
public Book saveBook(Book book){
System.out.println("saveBook: "+book);
book = bookRepository.save(book);
return book;
}
@CachePut(key = "#result.id")
public Book updateBook(Book book){
System.out.println("updateBook: "+book);
book = bookRepository.save(book);
return book;
}
/**
* @CacheEvict(beforeInvocation = true)删除缓存中过时或未使用的数据
* beforeInvocation = true: 在方法执行前删除
*/
@CacheEvict(beforeInvocation = true)
public void deleteBook(Integer id){
System.out.println("deleteBook: "+id);
bookRepository.deleteById(id);
}
}
BookController控制器
package com.study.springboot_cache.controller;
import com.study.springboot_cache.entity.Book;
import com.study.springboot_cache.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/book")
public class BookController {
@Autowired
private BookService bookService;
@PostMapping
public String saveBook(@RequestBody Book book){
Book resultBook = bookService.saveBook(book);
return resultBook.toString();
}
@GetMapping("/{id}")
public String getBookById(@PathVariable Integer id){
Book resultBook = bookService.getBookById(id);
return resultBook.toString();
}
@PutMapping
public String updateBook(@RequestBody Book book){
Book resultBook = bookService.updateBook(book);
return resultBook.toString();
}
@DeleteMapping
public String deleteBook(@PathVariable Integer id){
bookService.deleteBook(id);
return "删除成功!";
}
}
SpringbootCacheApplication启动类
package com.study.springboot_cache;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching //启用缓存
public class SpringbootCacheApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootCacheApplication.class, args);
}
}
启动项目,使用Postman测试
1、向表中添加数据
2、查询数据
第一次查询时,会调用方法,在控制台打印出SQL语句;
第二次使用相同参数查询时,使用缓存中的数据,不会调用方法,控制台没有输出
3、 更改数据
更改数据,再查询两次,第二次查询也是使用缓存中数据,不调用方法,控制台不打印SQL语句