Spring Boot 數(shù)據(jù)緩存與性能優(yōu)化實(shí)戰(zhàn)指南
Spring Boot 數(shù)據(jù)緩存與性能優(yōu)化
23.1 學(xué)習(xí)目標(biāo)與重點(diǎn)提示
學(xué)習(xí)目標(biāo):掌握Spring Boot數(shù)據(jù)緩存與性能優(yōu)化的核心概念與使用方法,包括數(shù)據(jù)緩存的定義與特點(diǎn)、Spring Boot與數(shù)據(jù)緩存的集成、Spring Boot與數(shù)據(jù)緩存的配置、Spring Boot與數(shù)據(jù)緩存的基本方法、Spring Boot的實(shí)際應(yīng)用場(chǎng)景,學(xué)會(huì)在實(shí)際開(kāi)發(fā)中處理數(shù)據(jù)緩存與性能優(yōu)化問(wèn)題。
重點(diǎn):數(shù)據(jù)緩存的定義與特點(diǎn)、Spring Boot與數(shù)據(jù)緩存的集成、Spring Boot與數(shù)據(jù)緩存的配置、Spring Boot與數(shù)據(jù)緩存的基本方法、Spring Boot的實(shí)際應(yīng)用場(chǎng)景。
23.2 數(shù)據(jù)緩存概述
數(shù)據(jù)緩存是Java開(kāi)發(fā)中的重要組件。
23.2.1 數(shù)據(jù)緩存的定義
定義:數(shù)據(jù)緩存是一種存儲(chǔ)機(jī)制,用于將常用數(shù)據(jù)存儲(chǔ)在高速存儲(chǔ)設(shè)備中,以便快速訪問(wèn)。
作用:
- 提高應(yīng)用程序的性能。
- 減少數(shù)據(jù)庫(kù)的訪問(wèn)次數(shù)。
- 提高用戶體驗(yàn)。
常見(jiàn)的數(shù)據(jù)緩存:
- EhCache:Apache EhCache是一款開(kāi)源的緩存庫(kù)。
- Caffeine:Caffeine是一款高性能的緩存庫(kù)。
- Redis:Redis是一款開(kāi)源的緩存服務(wù)器。
? 結(jié)論:數(shù)據(jù)緩存是一種存儲(chǔ)機(jī)制,作用是提高應(yīng)用程序的性能、減少數(shù)據(jù)庫(kù)的訪問(wèn)次數(shù)、提高用戶體驗(yàn)。
23.2.2 數(shù)據(jù)緩存的特點(diǎn)
定義:數(shù)據(jù)緩存的特點(diǎn)是指數(shù)據(jù)緩存的特性。
特點(diǎn):
- 高速訪問(wèn):數(shù)據(jù)緩存提供高速訪問(wèn)。
- 數(shù)據(jù)一致性:數(shù)據(jù)緩存提供數(shù)據(jù)一致性。
- 可擴(kuò)展性:數(shù)據(jù)緩存可以擴(kuò)展到多個(gè)應(yīng)用程序之間的緩存通信。
- 易用性:數(shù)據(jù)緩存提供易用的編程模型。
? 結(jié)論:數(shù)據(jù)緩存的特點(diǎn)包括高速訪問(wèn)、數(shù)據(jù)一致性、可擴(kuò)展性、易用性。
23.3 Spring Boot與數(shù)據(jù)緩存的集成
Spring Boot與數(shù)據(jù)緩存的集成是Java開(kāi)發(fā)中的重要內(nèi)容。
23.3.1 集成EhCache的步驟
定義:集成EhCache的步驟是指使用Spring Boot與EhCache集成的方法。
步驟:
- 創(chuàng)建Spring Boot項(xiàng)目。
- 添加所需的依賴。
- 配置EhCache。
- 創(chuàng)建數(shù)據(jù)訪問(wèn)層。
- 創(chuàng)建業(yè)務(wù)層。
- 創(chuàng)建控制器類。
- 測(cè)試應(yīng)用。
示例:
pom.xml文件中的依賴:
<dependencies>
<!-- Web依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Data JPA依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- H2數(shù)據(jù)庫(kù)依賴 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- EhCache依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<!-- 測(cè)試依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>application.properties文件中的EhCache配置:
# 服務(wù)器端口 server.port=8080 # 數(shù)據(jù)庫(kù)連接信息 spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driver-class-name=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password # JPA配置 spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true # H2數(shù)據(jù)庫(kù)控制臺(tái) spring.h2.console.enabled=true spring.h2.console.path=/h2-console # EhCache配置 spring.cache.type=ehcache spring.cache.ehcache.config=classpath:ehcache.xml
ehcache.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<defaultCache
maxEntriesLocalHeap="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120">
</defaultCache>
<cache name="productCache"
maxEntriesLocalHeap="1000"
eternal="false"
timeToIdleSeconds="60"
timeToLiveSeconds="60"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120">
</cache>
</ehcache>實(shí)體類:
import javax.persistence.*;
@Entity
@Table(name = "product")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String productId;
private String productName;
private double price;
private int sales;
public Product() {
}
public Product(String productId, String productName, double price, int sales) {
this.productId = productId;
this.productName = productName;
this.price = price;
this.sales = sales;
}
// Getter和Setter方法
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getSales() {
return sales;
}
public void setSales(int sales) {
this.sales = sales;
}
@Override
public String toString() {
return "Product{" +
"id=" + id +
", productId='" + productId + '\'' +
", productName='" + productName + '\'' +
", price=" + price +
", sales=" + sales +
'}';
}
}Repository接口:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
}Service類:
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;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
@Transactional
@CachePut(value = "productCache", key = "#product.id")
public Product addProduct(Product product) {
return productRepository.save(product);
}
@Transactional
@CachePut(value = "productCache", key = "#product.id")
public Product updateProduct(Product product) {
return productRepository.save(product);
}
@Transactional
@CacheEvict(value = "productCache", key = "#id")
public void deleteProduct(Long id) {
productRepository.deleteById(id);
}
@Transactional(readOnly = true)
@Cacheable(value = "productCache", key = "#id")
public Product getProductById(Long id) {
System.out.println("從數(shù)據(jù)庫(kù)查詢產(chǎn)品:" + id);
return productRepository.findById(id).orElse(null);
}
@Transactional(readOnly = true)
public List<Product> getAllProducts() {
return productRepository.findAll();
}
}控制器類:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/products")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("/")
public List<Product> getAllProducts() {
return productService.getAllProducts();
}
@PostMapping("/")
public Product addProduct(@RequestBody Product product) {
return productService.addProduct(product);
}
@PutMapping("/{id}")
public Product updateProduct(@PathVariable Long id, @RequestBody Product product) {
product.setId(id);
return productService.updateProduct(product);
}
@DeleteMapping("/{id}")
public void deleteProduct(@PathVariable Long id) {
productService.deleteProduct(id);
}
@GetMapping("/{id}")
public Product getProductById(@PathVariable Long id) {
return productService.getProductById(id);
}
}應(yīng)用啟動(dòng)類:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class ProductApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApplication.class, args);
}
@Autowired
private ProductService productService;
public void run(String... args) {
// 初始化數(shù)據(jù)
productService.addProduct(new Product("P001", "手機(jī)", 1000.0, 100));
productService.addProduct(new Product("P002", "電腦", 5000.0, 50));
productService.addProduct(new Product("P003", "電視", 3000.0, 80));
productService.addProduct(new Product("P004", "手表", 500.0, 200));
productService.addProduct(new Product("P005", "耳機(jī)", 300.0, 150));
}
}測(cè)試類:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ProductApplicationTests {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
}
@Test
void testGetProductById() {
Product product1 = restTemplate.getForObject("http://localhost:" + port + "/api/products/1", Product.class);
assertThat(product1).isNotNull();
assertThat(product1.getProductId()).isEqualTo("P001");
Product product2 = restTemplate.getForObject("http://localhost:" + port + "/api/products/1", Product.class);
assertThat(product2).isNotNull();
assertThat(product2.getProductId()).isEqualTo("P001");
}
@Test
void testAddProduct() {
Product product = new Product("P006", "平板", 2000.0, 70);
Product savedProduct = restTemplate.postForObject("http://localhost:" + port + "/api/products/", product, Product.class);
assertThat(savedProduct).isNotNull();
assertThat(savedProduct.getProductId()).isEqualTo("P006");
}
@Test
void testUpdateProduct() {
Product product = new Product("P001", "手機(jī)", 1500.0, 120);
restTemplate.put("http://localhost:" + port + "/api/products/1", product);
Product updatedProduct = restTemplate.getForObject("http://localhost:" + port + "/api/products/1", Product.class);
assertThat(updatedProduct).isNotNull();
assertThat(updatedProduct.getPrice()).isEqualTo(1500.0);
}
@Test
void testDeleteProduct() {
restTemplate.delete("http://localhost:" + port + "/api/products/2");
Product product = restTemplate.getForObject("http://localhost:" + port + "/api/products/2", Product.class);
assertThat(product).isNull();
}
}? 結(jié)論:集成EhCache的步驟包括創(chuàng)建Spring Boot項(xiàng)目、添加所需的依賴、配置EhCache、創(chuàng)建數(shù)據(jù)訪問(wèn)層、創(chuàng)建業(yè)務(wù)層、創(chuàng)建控制器類、測(cè)試應(yīng)用。
23.4 Spring Boot與數(shù)據(jù)緩存的配置
Spring Boot與數(shù)據(jù)緩存的配置是Java開(kāi)發(fā)中的重要內(nèi)容。
23.4.1 配置Caffeine緩存
定義:配置Caffeine緩存是指使用Spring Boot與Caffeine緩存集成的方法。
步驟:
- 創(chuàng)建Spring Boot項(xiàng)目。
- 添加所需的依賴。
- 配置Caffeine緩存。
- 創(chuàng)建數(shù)據(jù)訪問(wèn)層。
- 創(chuàng)建業(yè)務(wù)層。
- 創(chuàng)建控制器類。
- 測(cè)試應(yīng)用。
示例:
pom.xml文件中的依賴:
<dependencies>
<!-- Web依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Data JPA依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- H2數(shù)據(jù)庫(kù)依賴 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Caffeine依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<!-- 測(cè)試依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>application.properties文件中的Caffeine緩存配置:
# 服務(wù)器端口 server.port=8080 # 數(shù)據(jù)庫(kù)連接信息 spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driver-class-name=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password # JPA配置 spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true # H2數(shù)據(jù)庫(kù)控制臺(tái) spring.h2.console.enabled=true spring.h2.console.path=/h2-console # Caffeine緩存配置 spring.cache.type=caffeine spring.cache.caffeine.spec=maximumSize=1000,expireAfterWrite=60s
控制器類:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/products")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("/")
public List<Product> getAllProducts() {
return productService.getAllProducts();
}
@PostMapping("/")
public Product addProduct(@RequestBody Product product) {
return productService.addProduct(product);
}
@PutMapping("/{id}")
public Product updateProduct(@PathVariable Long id, @RequestBody Product product) {
product.setId(id);
return productService.updateProduct(product);
}
@DeleteMapping("/{id}")
public void deleteProduct(@PathVariable Long id) {
productService.deleteProduct(id);
}
@GetMapping("/{id}")
public Product getProductById(@PathVariable Long id) {
return productService.getProductById(id);
}
}測(cè)試類:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ProductApplicationTests {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
}
@Test
void testGetProductById() {
Product product1 = restTemplate.getForObject("http://localhost:" + port + "/api/products/1", Product.class);
assertThat(product1).isNotNull();
assertThat(product1.getProductId()).isEqualTo("P001");
Product product2 = restTemplate.getForObject("http://localhost:" + port + "/api/products/1", Product.class);
assertThat(product2).isNotNull();
assertThat(product2.getProductId()).isEqualTo("P001");
}
@Test
void testAddProduct() {
Product product = new Product("P006", "平板", 2000.0, 70);
Product savedProduct = restTemplate.postForObject("http://localhost:" + port + "/api/products/", product, Product.class);
assertThat(savedProduct).isNotNull();
assertThat(savedProduct.getProductId()).isEqualTo("P006");
}
@Test
void testUpdateProduct() {
Product product = new Product("P001", "手機(jī)", 1500.0, 120);
restTemplate.put("http://localhost:" + port + "/api/products/1", product);
Product updatedProduct = restTemplate.getForObject("http://localhost:" + port + "/api/products/1", Product.class);
assertThat(updatedProduct).isNotNull();
assertThat(updatedProduct.getPrice()).isEqualTo(1500.0);
}
@Test
void testDeleteProduct() {
restTemplate.delete("http://localhost:" + port + "/api/products/2");
Product product = restTemplate.getForObject("http://localhost:" + port + "/api/products/2", Product.class);
assertThat(product).isNull();
}
}? 結(jié)論:配置Caffeine緩存是指使用Spring Boot與Caffeine緩存集成的方法,步驟包括創(chuàng)建Spring Boot項(xiàng)目、添加所需的依賴、配置Caffeine緩存、創(chuàng)建數(shù)據(jù)訪問(wèn)層、創(chuàng)建業(yè)務(wù)層、創(chuàng)建控制器類、測(cè)試應(yīng)用。
23.5 Spring Boot與數(shù)據(jù)緩存的基本方法
Spring Boot與數(shù)據(jù)緩存的基本方法包括使用@Cacheable、@CachePut、@CacheEvict注解。
23.5.1 使用@Cacheable注解
定義:使用@Cacheable注解是指Spring Boot與數(shù)據(jù)緩存集成的基本方法之一。
作用:
- 實(shí)現(xiàn)數(shù)據(jù)緩存。
- 提高應(yīng)用程序的性能。
示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
@Transactional(readOnly = true)
@Cacheable(value = "productCache", key = "#id")
public Product getProductById(Long id) {
System.out.println("從數(shù)據(jù)庫(kù)查詢產(chǎn)品:" + id);
return productRepository.findById(id).orElse(null);
}
@Transactional(readOnly = true)
public List<Product> getAllProducts() {
return productRepository.findAll();
}
}? 結(jié)論:使用@Cacheable注解是指Spring Boot與數(shù)據(jù)緩存集成的基本方法之一,作用是實(shí)現(xiàn)數(shù)據(jù)緩存、提高應(yīng)用程序的性能。
23.5.2 使用@CachePut注解
定義:使用@CachePut注解是指Spring Boot與數(shù)據(jù)緩存集成的基本方法之一。
作用:
- 實(shí)現(xiàn)數(shù)據(jù)緩存。
- 提高應(yīng)用程序的性能。
示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
@Transactional
@CachePut(value = "productCache", key = "#product.id")
public Product addProduct(Product product) {
return productRepository.save(product);
}
@Transactional
@CachePut(value = "productCache", key = "#product.id")
public Product updateProduct(Product product) {
return productRepository.save(product);
}
@Transactional(readOnly = true)
@Cacheable(value = "productCache", key = "#id")
public Product getProductById(Long id) {
System.out.println("從數(shù)據(jù)庫(kù)查詢產(chǎn)品:" + id);
return productRepository.findById(id).orElse(null);
}
@Transactional(readOnly = true)
public List<Product> getAllProducts() {
return productRepository.findAll();
}
}? 結(jié)論:使用@CachePut注解是指Spring Boot與數(shù)據(jù)緩存集成的基本方法之一,作用是實(shí)現(xiàn)數(shù)據(jù)緩存、提高應(yīng)用程序的性能。
23.5.3 使用@CacheEvict注解
定義:使用@CacheEvict注解是指Spring Boot與數(shù)據(jù)緩存集成的基本方法之一。
作用:
- 實(shí)現(xiàn)數(shù)據(jù)緩存。
- 提高應(yīng)用程序的性能。
示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
@Transactional
@CachePut(value = "productCache", key = "#product.id")
public Product addProduct(Product product) {
return productRepository.save(product);
}
@Transactional
@CachePut(value = "productCache", key = "#product.id")
public Product updateProduct(Product product) {
return productRepository.save(product);
}
@Transactional
@CacheEvict(value = "productCache", key = "#id")
public void deleteProduct(Long id) {
productRepository.deleteById(id);
}
@Transactional(readOnly = true)
@Cacheable(value = "productCache", key = "#id")
public Product getProductById(Long id) {
System.out.println("從數(shù)據(jù)庫(kù)查詢產(chǎn)品:" + id);
return productRepository.findById(id).orElse(null);
}
@Transactional(readOnly = true)
public List<Product> getAllProducts() {
return productRepository.findAll();
}
}? 結(jié)論:使用@CacheEvict注解是指Spring Boot與數(shù)據(jù)緩存集成的基本方法之一,作用是實(shí)現(xiàn)數(shù)據(jù)緩存、提高應(yīng)用程序的性能。
23.6 Spring Boot的實(shí)際應(yīng)用場(chǎng)景
在實(shí)際開(kāi)發(fā)中,Spring Boot數(shù)據(jù)緩存與性能優(yōu)化的應(yīng)用場(chǎng)景非常廣泛,如:
- 實(shí)現(xiàn)產(chǎn)品信息的緩存。
- 實(shí)現(xiàn)用戶信息的緩存。
- 實(shí)現(xiàn)訂單信息的緩存。
- 實(shí)現(xiàn)日志信息的緩存。
示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class ProductApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApplication.class, args);
}
@Autowired
private ProductService productService;
public void run(String... args) {
// 初始化數(shù)據(jù)
productService.addProduct(new Product("P001", "手機(jī)", 1000.0, 100));
productService.addProduct(new Product("P002", "電腦", 5000.0, 50));
productService.addProduct(new Product("P003", "電視", 3000.0, 80));
productService.addProduct(new Product("P004", "手表", 500.0, 200));
productService.addProduct(new Product("P005", "耳機(jī)", 300.0, 150));
}
}
@Service
class ProductService {
@Autowired
private ProductRepository productRepository;
@Transactional
@CachePut(value = "productCache", key = "#product.id")
public Product addProduct(Product product) {
return productRepository.save(product);
}
@Transactional
@CachePut(value = "productCache", key = "#product.id")
public Product updateProduct(Product product) {
return productRepository.save(product);
}
@Transactional
@CacheEvict(value = "productCache", key = "#id")
public void deleteProduct(Long id) {
productRepository.deleteById(id);
}
@Transactional(readOnly = true)
@Cacheable(value = "productCache", key = "#id")
public Product getProductById(Long id) {
System.out.println("從數(shù)據(jù)庫(kù)查詢產(chǎn)品:" + id);
return productRepository.findById(id).orElse(null);
}
@Transactional(readOnly = true)
public List<Product> getAllProducts() {
return productRepository.findAll();
}
}
@RestController
@RequestMapping("/api/products")
class ProductController {
@Autowired
private ProductService productService;
@GetMapping("/")
public List<Product> getAllProducts() {
return productService.getAllProducts();
}
@PostMapping("/")
public Product addProduct(@RequestBody Product product) {
return productService.addProduct(product);
}
@PutMapping("/{id}")
public Product updateProduct(@PathVariable Long id, @RequestBody Product product) {
product.setId(id);
return productService.updateProduct(product);
}
@DeleteMapping("/{id}")
public void deleteProduct(@PathVariable Long id) {
productService.deleteProduct(id);
}
@GetMapping("/{id}")
public Product getProductById(@PathVariable Long id) {
return productService.getProductById(id);
}
}
// 測(cè)試類
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ProductApplicationTests {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
}
@Test
void testGetProductById() {
Product product1 = restTemplate.getForObject("http://localhost:" + port + "/api/products/1", Product.class);
assertThat(product1).isNotNull();
assertThat(product1.getProductId()).isEqualTo("P001");
Product product2 = restTemplate.getForObject("http://localhost:" + port + "/api/products/1", Product.class);
assertThat(product2).isNotNull();
assertThat(product2.getProductId()).isEqualTo("P001");
}
@Test
void testAddProduct() {
Product product = new Product("P006", "平板", 2000.0, 70);
Product savedProduct = restTemplate.postForObject("http://localhost:" + port + "/api/products/", product, Product.class);
assertThat(savedProduct).isNotNull();
assertThat(savedProduct.getProductId()).isEqualTo("P006");
}
@Test
void testUpdateProduct() {
Product product = new Product("P001", "手機(jī)", 1500.0, 120);
restTemplate.put("http://localhost:" + port + "/api/products/1", product);
Product updatedProduct = restTemplate.getForObject("http://localhost:" + port + "/api/products/1", Product.class);
assertThat(updatedProduct).isNotNull();
assertThat(updatedProduct.getPrice()).isEqualTo(1500.0);
}
@Test
void testDeleteProduct() {
restTemplate.delete("http://localhost:" + port + "/api/products/2");
Product product = restTemplate.getForObject("http://localhost:" + port + "/api/products/2", Product.class);
assertThat(product).isNull();
}
}輸出結(jié)果:
- 訪問(wèn)http://localhost:8080/api/products/1:第一次訪問(wèn)從數(shù)據(jù)庫(kù)查詢,第二次訪問(wèn)從緩存查詢。
- 控制臺(tái)輸出:
從數(shù)據(jù)庫(kù)查詢產(chǎn)品:1
? 結(jié)論:在實(shí)際開(kāi)發(fā)中,Spring Boot數(shù)據(jù)緩存與性能優(yōu)化的應(yīng)用場(chǎng)景非常廣泛,需要根據(jù)實(shí)際問(wèn)題選擇合適的緩存策略。
總結(jié)
本章我們學(xué)習(xí)了Spring Boot數(shù)據(jù)緩存與性能優(yōu)化,包括數(shù)據(jù)緩存的定義與特點(diǎn)、Spring Boot與數(shù)據(jù)緩存的集成、Spring Boot與數(shù)據(jù)緩存的配置、Spring Boot與數(shù)據(jù)緩存的基本方法、Spring Boot的實(shí)際應(yīng)用場(chǎng)景,學(xué)會(huì)了在實(shí)際開(kāi)發(fā)中處理數(shù)據(jù)緩存與性能優(yōu)化問(wèn)題。其中,數(shù)據(jù)緩存的定義與特點(diǎn)、Spring Boot與數(shù)據(jù)緩存的集成、Spring Boot與數(shù)據(jù)緩存的配置、Spring Boot與數(shù)據(jù)緩存的基本方法、Spring Boot的實(shí)際應(yīng)用場(chǎng)景是本章的重點(diǎn)內(nèi)容。從下一章開(kāi)始,我們將學(xué)習(xí)Spring Boot的其他組件、微服務(wù)等內(nèi)容。
到此這篇關(guān)于Spring Boot 數(shù)據(jù)緩存與性能優(yōu)化實(shí)戰(zhàn)指南的文章就介紹到這了,更多相關(guān)Spring Boot 數(shù)據(jù)緩存與性能優(yōu)化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot整合canal實(shí)現(xiàn)數(shù)據(jù)緩存一致性解決方案
- Springboot使用@Cacheable注解實(shí)現(xiàn)數(shù)據(jù)緩存
- SpringBoot中整合Ehcache實(shí)現(xiàn)熱點(diǎn)數(shù)據(jù)緩存的詳細(xì)過(guò)程
- SpringBoot整合Redis實(shí)現(xiàn)高并發(fā)數(shù)據(jù)緩存的示例講解
- SpringBoot整合Redis實(shí)現(xiàn)熱點(diǎn)數(shù)據(jù)緩存的示例代碼
- SpringBoot與Spring中數(shù)據(jù)緩存Cache超詳細(xì)講解
- 基于SpringBoot Actuator與Prometheus自定義指標(biāo)監(jiān)控與性能優(yōu)化實(shí)戰(zhàn)指南
- springboot連接mongo性能優(yōu)化參數(shù)配置方式
- 簡(jiǎn)單聊聊SpringBoot性能優(yōu)化的12個(gè)小技巧
相關(guān)文章
SpringBoot2.0 中 HikariCP 數(shù)據(jù)庫(kù)連接池原理解析
這篇文章主要介紹了SpringBoot2.0 中 HikariCP 數(shù)據(jù)庫(kù)連接池原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
Java利用Netty時(shí)間輪實(shí)現(xiàn)延時(shí)任務(wù)
時(shí)間輪是一種可以執(zhí)行定時(shí)任務(wù)的數(shù)據(jù)結(jié)構(gòu)和算法。本文將為大家詳細(xì)講解一下Java如何利用Netty時(shí)間輪算法實(shí)現(xiàn)延時(shí)任務(wù),感興趣的小伙伴可以了解一下2022-08-08
Spring 自定義事件監(jiān)聽(tīng)器實(shí)現(xiàn)步驟詳解
本文詳細(xì)介紹了Spring自定義事件監(jiān)聽(tīng)器的實(shí)現(xiàn)步驟,包括定義事件、發(fā)布事件、監(jiān)聽(tīng)并處理事件等,結(jié)合異步和自定義線程池等擴(kuò)展能力,通過(guò)標(biāo)準(zhǔn)化步驟,提供代碼示例和關(guān)鍵說(shuō)明,幫助開(kāi)發(fā)者實(shí)現(xiàn)事件驅(qū)動(dòng)架構(gòu),感興趣的朋友跟隨小編一起看看吧2025-12-12
JpaRepository?實(shí)現(xiàn)簡(jiǎn)單條件查詢
這篇文章主要介紹了JpaRepository?實(shí)現(xiàn)簡(jiǎn)單條件查詢,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
Spring Boot Maven Plugin打包異常解決方案
這篇文章主要介紹了Spring Boot Maven Plugin打包異常解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
Java應(yīng)用程序的CPU使用率飆升原因詳細(xì)分析
這篇文章主要介紹了Java應(yīng)用程序的CPU使用率飆升原因詳細(xì)分析,在 Java 中,我們使用 JVM 進(jìn)行線程調(diào)度,所以一般來(lái)說(shuō),線程的調(diào)度有兩種模式:分時(shí)調(diào)度和搶占式調(diào)度,線程和進(jìn)程在阻塞或者等待時(shí),都不會(huì)使用 CPU 資源,需要的朋友可以參考下2024-01-01
log4j如何根據(jù)變量動(dòng)態(tài)生成文件名
這篇文章主要介紹了log4j如何根據(jù)變量動(dòng)態(tài)生成文件名方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12

