1、爲什麼使用緩存
我們都知道,一個程序的瓶頸通常都在數據庫,很多場景需要獲取相同的數據。比如網站頁面數據等,
需要一次次的請求數據庫,導致大部分時間都浪費在數據庫查詢和方法調用上,這時就可以利用到緩存來緩解這個問題。
2、聲明式緩存
Spring 定義 CacheManager 和 Cache 接口用來統一不同的緩存技術。例如 JCache、 EhCache、 Hazelcast、 Guava、 Redis 等。
在使用 Spring 集成 Cache 的時候,我們需要註冊實現的 CacheManager 的 Bean。
Spring Boot 爲我們自動配置了 JcacheCacheConfiguration、 EhCacheCacheConfiguration、HazelcastCacheConfiguration、
GuavaCacheConfiguration、RedisCacheConfiguration、SimpleCacheConfiguration 等。
3、默認使用 ConcurrenMapCacheManager
在我們不使用其他第三方緩存依賴的時候,springboot自動採用ConcurrenMapCacheManager作爲緩存管理器。
4、使用過程需要注意什麼
1、明確哪些方法需要使用緩存,正確使用使得程序變得高效,不會導致編碼累贅
2、用於解決哪些實際問題
5、下面是一個簡單的例子,只截圖了關鍵使用部分,springboot+mybatis+mysql+spring cahce實現的緩存效果
依賴
<!-- mysql連接類-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--alibaba連接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.29</version>
</dependency>
<!-- 開啓web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- cache緩存環境-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--springboot整合mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
properties.yml配置 cache無需配置,只配置了mysql#mysql數據庫連接
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/hotel?serverTimezone=UTC
username: root
password: aaaaaa
開啓緩存功能,需要正在啓動類上加註解@EnableCaching
@SpringBootApplication
//開啓緩存
@EnableCaching
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
此處實體類、dao層、service層省略了,只展示controller部分代碼,因爲該cache功能主要是用註解來實現緩存效果
package com.hotel.demo.web;
import com.hotel.demo.bean.Style;
import com.hotel.demo.dao.JpaStyleDao;
import com.hotel.demo.service.StyleService;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
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.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;
import javax.transaction.Transactional;
import java.util.List;
import java.util.jar.JarEntry;
@RestController
@RequestMapping("/style")
@Transactional
public class StyleController {
private static final Logger logger = LoggerFactory.getLogger(StyleController.class);
@Autowired
StyleService styleService;
@Autowired
JpaStyleDao jpaStyleDao;
/*插入數據*/
@RequestMapping(value = "/add", method = RequestMethod.POST)
@ApiOperation(value = "添加房間類型", notes = "添加房間類型")
@CachePut(value = "style")
public int add() throws RuntimeException {
Style style = new Style();
style.setStyle("大房");
style.setMoney(125.0);
style.setFacilities("衛生間、健生房");
style.setMessage("可住兩人");
return styleService.add(style);
}
//更新數據
/*@PathVariable@RequestParam 一起使用 請求方式http://127.0.0.1:8080/style/update/5?style=大房*/
@RequestMapping(value = "/update/{id}", method = RequestMethod.PUT)
@ApiOperation(value = "更新數據", notes = "更新數據")
@ApiImplicitParams({
@ApiImplicitParam(name = "style", value = "類型名", required = true, dataType = "String", paramType = "path"),
@ApiImplicitParam(name = "id", value = "類型id", required = true, dataType = "int", paramType = "path")
})
@CachePut(value="style",key="#id")
public int update(@PathVariable int id, @RequestParam(value = "style", required = true) String style) {
/* Style style = new Style();
style.setId(id);
style.setStyle(styles);
style.setMoney(126.0);
style.setFacilities("衛生間、健生房");
style.setMessage("可住兩人");
return styleService.update(style);*/
return styleService.update(style, id);
}
//刪除數據
@ApiOperation(value = "刪除數據", notes = "刪除數據")
@ApiImplicitParam(name = "id", value = "類型ID", required = true, dataType = "int", paramType = "path")
@RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
@CacheEvict(value="style",key="#id")
public void delete(@PathVariable int id) {
styleService.delete(id);
}
//按照ID查找數據
@ApiOperation(value = "按照ID查找數據", notes = "按照ID查找數據")
@ApiImplicitParam(name = "id", value = "類型ID", required = true, dataType = "int", paramType = "path")
@RequestMapping(value = "/findById/{id}", method = RequestMethod.GET)
//打開該方法的緩存
@Cacheable(value = "style", key = "#id")
public Style findById(@PathVariable int id) {
long startTime = System.currentTimeMillis();
Style style = styleService.findById(id);
long endTime = System.currentTimeMillis();
logger.info("start -->end時間差" + (endTime - startTime));
return style;
}
//查找所有數據
@ApiIgnore//使用該註解忽略這個API
@ApiOperation(value = "查找所有數據", notes = "查找所有數據")
@RequestMapping(value = "/findAll", method = RequestMethod.GET)
@Cacheable(value = "emp")
public List<Style> findAll() {
return styleService.findAll();
}
}
大家還需要關注類方法上的註解@Cacheable()、 @CacheEvict()、@CachePut()
解釋測試方法
1.add方法
方法中使用到了@CachePut註解,這個註解直接將返回值放入緩存中,通常用於保存和修改方法中
2.findAll、findById方法
方法中使用到了@Cacheable註解,這個註解在執行前先查看緩存中是不是已經存在了,如果存在,直接返回。如果不存在,將方法的返回值放入緩存。
3.delete方法
方法中使用到了@CacheEvict註解,這個註解在執行方法執行成功後會將操作的對象從緩存中移除,僅針對某一次的緩存
@CacheEvict也可以將所有緩存刪除,寫法爲 @CacheEvict(value = “house”, allEntries = true) allEntries不寫默認爲false 只刪除註解方法指定的緩存
參數解釋
如@Cacheable(value = “style”, key = “#id”)中value指的是給該次緩存取一個名字自定義,key爲該緩存的鍵
1.當我們要使用root對象的屬性作爲key時我們也可以將“#root”省略,因爲Spring默認使用的就是root對象的屬性。 如
@Cacheable(value = "emp" ,key = "targetClass + methodName +#p0")
public List<NewJob> queryAll(User uid) {
return newJobDao.findAllByUid(uid);
}
2.使用方法參數時我們可以直接使用“#參數名”或者“#p參數index”。 如:
@Cacheable(value="users", key="#id")
public void delete(@PathVariable int id) {
styleService.delete(id);
}
或
@Cacheable(value="users", key="#p0")
public void delete(@PathVariable int id) {
styleService.delete(id);
}
注意
這個緩存註解對的意義是當查詢有緩存存在時,直接返回緩存值,而不會再去執行註解的方法,
參考findById方法的時間差打印,執行兩次findById,只會執行一次打印,第二次執行直接返回,沒有執行該方法
如果大家想讓緩存效果更明顯一點,可以使用springboot+jpa+mybatis+cache,需要開啓show-sql: true 打印sql語句
在執行的時候你會發現,當你執行第一次查詢時會打印sql,第二次就不會打印;