摘要:前言如題,今天介紹的數據緩存。說明確實做了數據緩存,第二次的測試結果是從數據緩存中獲取的,并沒有直接查數據庫。為為的數據做了緩存插入數據返回的結果數據庫中的結果訪問結果如下圖。后語以上為數據緩存的教程。
微信公眾號:一個優秀的廢人前言
如有問題或建議,請后臺留言,我會盡力解決你的問題。
如題,今天介紹 SpringBoot 的數據緩存。做過開發的都知道程序的瓶頸在于數據庫,我們也知道內存的速度是大大快于硬盤的,當需要重復獲取相同數據時,一次又一次的請求數據庫或者遠程服務,導致大量時間耗費在數據庫查詢或遠程方法調用上,導致性能的惡化,這便是數據緩存要解決的問題。
Spring 的緩存支持Spring 定義了 org.springframework.cache.CacheManager 和 org.springframework.cache.Cache 接口用于統一不同的緩存技術。其中,CacheManager 是 Spring 提供的各種緩存技術的抽象接口,Cache 接口則是包含了緩存的各種操作(增加,刪除,獲取緩存,一般不會直接和此接口打交道)。
1、Spring 支持的 CacheManager
針對不同的緩存技術,實現了不同的 CacheManager ,Spring 定義了下表所示的 CacheManager:
CacheManager | 描述 |
---|---|
SimpleCacheManager | 使用簡單的 Collection 來存儲緩存,主要用于測試 |
ConcurrentMapCacheManager | 使用 ConcurrentMap 來存儲緩存 |
NoOpCacheManager | 僅測試用途,不會實際緩存數據 |
EhCacheCacheManager | 使用 EhCache 作為緩存技術 |
GuavaCacheManager | 使用 Google Guava 的 GuavaCache 作為緩存技術 |
HazelcastCacheManager | 使用 Hazelcast 作為緩存技術 |
JCacheCacheManager | 支持 JCache(JSR-107) 標準的實現作為緩存技術,如 ApacheCommonsJCS |
RedisCacheManager | 使用 Redis 作為緩存技術 |
在使用以上任意一個實現的 CacheManager 的時候,需注冊實現的 CacheManager 的 Bean,如:
@Bean public EhCacheCacheManager cacheManager(CacheManager ehCacheCacheManager){ return new EhCacheCacheManager(ehCacheCacheManager); }
注意,每種緩存技術都有很多的額外配置,但配置 cacheManager 是必不可少的。
2、聲明式緩存注解
Spring 提供了 4 個注解來聲明緩存規則(又是使用注解式的 AOP 的一個例子)。4 個注解如下表示:
注解 | 解釋 |
---|---|
@Cacheable | 在方法執行前 Spring 先查看緩存中是否有數據,若有,則直接返回緩存數據;若無數據,調用方法將方法返回值放入緩存中 |
@CachePut | 無論怎樣,都會將方法的返回值放到緩存中。 |
@CacheEvict | 將一條或多條數據從緩存中刪除 |
@Caching | 可以通過 @Caching 注解組合多個注解策略在一個方法上 |
@Cacheable、@CachePut、@CacheEvict 都有 value 屬性,指定的是要使用的緩存名稱;key 屬性指定的是數據在緩存中存儲的鍵。
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 作為緩存技術,演示 @Cacheable、@CachePut、@CacheEvict。
1、準備工作
IDEA
JDK 1.8
SpringBoot 2.1.3
2、Pom.xml 文件依賴
4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.3.RELEASE com.nasus cache 0.0.1-SNAPSHOT cache cache Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-cache org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-web mysql mysql-connector-java runtime org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin
注釋很清楚,無需多言。不會就谷歌一下。
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、dao 層
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{ }
6、service 層
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、controller 層
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、application 開啟緩存功能
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 查詢語句,以及指定日志。說明這一次程序是直接查詢數據庫得到的結果。
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 語句打印,也無為id、key 為2的數據做了緩存這句話輸出。
說明 @Cacheable 確實做了數據緩存,第二次的測試結果是從數據緩存中獲取的,并沒有直接查數據庫。
2、測試 @CachePut
如下圖,postman 訪問?http://localhost:8080/student/put?插入數據:
下面是控制臺打印出了 SQL Insert 插入語句,以及指定日志。說明程序做了緩存。
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的數據做了緩存
插入數據返回的結果:
數據庫中的結果:
訪問 http://localhost:8080/student/able/4 Postman 結果如下圖。控制臺無輸出,驗證了 @CachePut 確實做了緩存,下圖數據是從緩存中獲取的。
3、測試 @CacheEvict
postman 訪問 http://localhost:8080/student/able/3 為 id = 3 的數據做緩存。
postman 再次訪問 http://localhost:8080/student/able/3 確認數據是從緩存中獲取的。
postman 訪問 http://localhost:8080/student/evit/3
從緩存中刪除 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_ 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的數據緩存
再次 postman 訪問 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 確實刪除了數據緩存。
源碼下載https://github.com/turoDog/Demo/tree/master/springboot_cache_demo
切換緩存技術切換緩存技術除了在 pom 文件加入相關依賴包配置以外,使用方式與上面的代碼演示一樣。
1、切換 EhCache
在 pom 中添加 Encache 依賴:
net.sf.ehcache ehcache
Ehcache 所需配置文件 ehcache.xml 只需放在類路徑(resource 目錄)下,SpringBoot 會自動掃描,如:
SpringBoot 會自動配置 EhcacheManager 的 Bean。
2、切換 Guava
只需在 pom 中加入 Guava 依賴即可:
com.google.guava guava 18.0
SpringBoot 會自動配置 GuavaCacheManager 的 Bean。
3、切換 RedisCache
與 Guava 一樣,只需在 pom 加入依賴即可:
org.springframework.boot spring-boot-starter-redis
SpringBoot 會自動配置 RedisCacheManager 以及 RedisTemplate 的 Bean。
此外,切換其他緩存技術的方式也是類似。這里不做贅述。
后語以上為 SpringBoot 數據緩存的教程。
如果本文對你哪怕有一丁點幫助,請幫忙點好看。
你的好看是我堅持寫作的動力。
另外,關注之后在發送 1024 可領取免費學習資料。資料內容詳情請看這篇舊文:Python、C++、Java、Linux、Go、前端、算法資料分享
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/73389.html
摘要:引入了新的環境和概要信息,是一種更揭秘與實戰六消息隊列篇掘金本文,講解如何集成,實現消息隊列。博客地址揭秘與實戰二數據緩存篇掘金本文,講解如何集成,實現緩存。 Spring Boot 揭秘與實戰(九) 應用監控篇 - HTTP 健康監控 - 掘金Health 信息是從 ApplicationContext 中所有的 HealthIndicator 的 Bean 中收集的, Spring...
摘要:作為微服務的基礎設施之一,背靠強大的生態社區,支撐技術體系。微服務實踐為系列講座,專題直播節,時長高達小時,包括目前最流行技術,深入源碼分析,授人以漁的方式,幫助初學者深入淺出地掌握,為高階從業人員拋磚引玉。 簡介 目前業界最流行的微服務架構正在或者已被各種規模的互聯網公司廣泛接受和認可,業已成為互聯網開發人員必備技術。無論是互聯網、云計算還是大數據,Java平臺已成為全棧的生態體系,...
閱讀 2750·2021-10-26 09:50
閱讀 2391·2021-10-11 11:08
閱讀 2132·2019-08-30 15:53
閱讀 1910·2019-08-30 15:44
閱讀 2386·2019-08-28 18:12
閱讀 2525·2019-08-26 13:59
閱讀 2858·2019-08-26 12:19
閱讀 2757·2019-08-26 12:09