春節就要到了,在回家之前要趕快把今年欠下的技術債還清。so,今天繼續。Spring Boot前面已經預熱了n篇部落格了,今天我們來繼續看如何在Spring Boot中解決資料緩存問題。本篇部落格是以初識在Spring Boot中使用JPA為基礎的,先了解如何實作資料通路,然後才好實作資料緩存。OK,對于Spring Boot尚有疑問的小夥伴可以先移步這裡從SpringMVC到Spring Boot,老司機請略過。
OK,廢話不多說,開始今天的技術之旅吧。
在實際開發中,對于要反複讀寫的資料,最好的處理方式是将之在記憶體中緩存一份,頻繁的資料庫通路會造成程式效率低下,同時記憶體的讀寫速度本身就要強于硬碟。Spring在這一方面給我們提供了諸多的處理手段,而Spring Boot又将這些處理方式進一步簡化,接下來我們就來看看如何在Spring Boot中解決資料緩存問題。
#建立Project并添加資料庫驅動
Spring Boot的建立方式還是和我們前文提到的建立方式一樣,不同的是這裡選擇添加的依賴不同,這裡我們添加Web、Cache和JPA依賴,如下圖:
建立成功之後,接下來添加資料庫驅動,我還是使用MySql,在pom.xml中添加資料庫驅動,如下:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
#配置application.properties
這個application.properties的配置還是和初識在Spring Boot中使用JPA一樣,各個參數的含義我這裡也不再贅述,我們直接來看代碼:
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/sang?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=sang
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jackson.serialization.indent_output=true
#建立實體類
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
private String name;
private String address;
private Integer age;
public Person() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Person(Long id, String name, String address, Integer age) {
this.id = id;
this.name = name;
this.address = address;
this.age = age;
}
}
#建立實體類的Repository
public interface PersonRepository extends JpaRepository<Person,Long> {
}
#建立業務類
業務接口
public interface DemoService {
public Person save(Person person);
public void remove(Long id);
public Person findOne(Person person);
}
實作類
@Service
public class DemoServiceImpl implements DemoService {
@Autowired
PersonRepository personRepository;
@CachePut(value = "people", key = "#person.id")
@Override
public Person save(Person person) {
Person p = personRepository.save(person);
System.out.println("為id、key為" + p.getId() + "資料做了緩存");
return p;
}
@CacheEvict(value = "people")
@Override
public void remove(Long id) {
System.out.println("删除了id、key為" + id + "的資料緩存");
personRepository.delete(id);
}
@Cacheable(value = "people", key = "#person.id")
@Override
public Person findOne(Person person) {
Person p = personRepository.findOne(person.getId());
System.out.println("為id、key為" + p.getId() + "資料做了緩存");
return p;
}
}@Service
public class DemoServiceImpl implements DemoService {
@Autowired
PersonRepository personRepository;
@CachePut(value = "people", key = "#person.id")
@Override
public Person save(Person person) {
Person p = personRepository.save(person);
System.out.println("為id、key為" + p.getId() + "資料做了緩存");
return p;
}
@CacheEvict(value = "people")
@Override
public void remove(Long id) {
System.out.println("删除了id、key為" + id + "的資料緩存");
personRepository.delete(id);
}
@Cacheable(value = "people", key = "#person.id")
@Override
public Person findOne(Person person) {
Person p = personRepository.findOne(person.getId());
System.out.println("為id、key為" + p.getId() + "資料做了緩存");
return p;
}
}
關于這個實作類我說如下幾點:
1.@CachePut表示緩存新添加的資料或者更新的資料到緩存中,兩個參數value表示緩存的名稱為people,key表示緩存的key為person的id
2.@CacheEvict表示從緩存people中删除key為id的資料
3.@Cacheable表示添加資料到緩存中,緩存名稱為people,緩存key為person的id屬性。
#建立Controller
@RestController
public class CacheController {
@Autowired
DemoService demoService;
@RequestMapping("/put")
public Person put(Person person) {
return demoService.save(person);
}
@RequestMapping("/able")
public Person cacheable(Person person) {
return demoService.findOne(person);
}
@RequestMapping("/evit")
public String evit(Long id) {
demoService.remove(id);
return "ok";
}
}
OK ,做完這一切我們就可以來測試我們剛剛寫的緩存了。
#測試
看我們的Controller,我們有三個位址要測試,一個一個來。當然,在 測試之前,我們先來看看初始狀态下的資料庫是什麼樣子的:
首先我們在浏覽器中通路http://localhost:8080/able?id=1,得到如下通路結果:
這個時候檢視控制台,輸出内容如下:
說是資料已經被緩存了,這個時候我們再繼續在浏覽器中重新整理繼續請求id為1的資料,會發現控制台不會繼續列印日志出來,就是因為資料已被存于緩存之中了。
接下來我們向浏覽器中輸入http://localhost:8080/put?age=47&name=奧巴牛&address=米國,通路結果如下:
這個時候檢視控制台列印的日志如下:
再檢視資料表,資料已插入成功:
此時,我們在浏覽器中輸入http://localhost:8080/able?id=106,通路剛剛插入的這條資料,結果如下:
這個時候檢視控制台,發現并沒有資料資料,就是因為資料已經處于緩存中了。
最後我們在浏覽器中輸入http://localhost:8080/evit?id=106,将資料從緩存中移除,通路結果如下:
這個時候檢視控制台,已經提示緩存移除掉了:
同時資料也從資料庫删除掉了,這個時候如果還需要該資料則需要我們繼續向表中添加資料。
#緩存技術切換
Spring Boot預設情況下使用ConcurrentMapCacheManager作為緩存技術,有的時候你可能想替換為其他的緩存方式,在Spring Boot中進行緩存的切換非常簡單,我這裡以Google提供的Guava為例,如果要使用這種緩存政策,隻需要添加相應的依賴即可,如下:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
就這樣就可以了。實際上在Spring Boot中,底層使用哪一種緩存我們并不必做過多考慮,切換的方式也很簡單,如上文引入相應的依賴即可,我們隻需要把上層的邏輯寫好即可。
本文案例下載下傳:
本文GitHub位址https://github.com/lenve/JavaEETest/tree/master/Test25-Cache.
更多Spring Boot案例請移步這裡從SpringMVC到Spring Boot
以上。