緩存是每個系統應該考慮的功能,它能夠用來加速系統的訪問,提高系統性能,例如要常常訪問的高頻熱點數據,例如某一個商品網站的商品信息,商品信息存儲在數據庫中,若每次訪問都要查詢數據庫的話,這樣的操做耗時太大了,因此咱們須要作一個緩存中間件,這樣咱們不須要查詢數據庫了,直接查詢緩存,若緩存中有,能夠直接返回,若沒有再查詢數據庫,而後放到緩存中,這樣咱們的系統性能就獲得了很大的提高,由於咱們的應用程序和緩存的交互是十分快的。java
還有一個應用場景是驗證碼,驗證碼是臨時性數據,一段時間內有效,用完就能夠刪除,這樣的數據無需存在數據庫中,因此可使用緩存來存儲這些臨時性數據,等用戶使用完後自動讓它清除。mysql
1、JSR107(瞭解)spring
JSR是Java規範請求,故名思議提交Java規範,你們一同遵照這個規範的話,會讓你們‘溝通’起來更加輕鬆。咱們一直使用的JDBC就一個訪問數據庫的一個規範的例子。JSR-107呢就是關於如何使用緩存的規範。sql
Java Caching定義了5個核心接口,分別是CachingProvider, CacheManager, Cache, Entry和Expiry:數據庫
1.CachingProvider定義了建立、配置、獲取、管理和控制多個CacheManager。一個應用能夠在運行期訪問多個CachingProvider。api
2.CacheManager定義了建立、配置、獲取、管理和控制多個惟一命名的Cache,這些Cache存在於CacheManager的上下文中。一個CacheManager僅被一個CachingProvider所擁有。數組
3.Cache是一個相似Map的數據結構並臨時存儲以Key爲索引的值。一個Cache僅被一個CacheManager所擁有。緩存
4.Entry是一個存儲在Cache中的key-value對。數據結構
5.Expiry每個存儲在Cache中的條目有一個定義的有效期。一旦超過這個時間,條目爲過時的狀態。一旦過時,條目將不可訪問、更新和刪除。緩存有效期能夠經過ExpiryPolicy設置。mybatis
使用時須要導入以下包:
<dependency> <groupId>javax.cache</groupId> <artifactId>cache-api</artifactId> </dependency>
JSR107在真正生產開發當中使用的很少,爲了簡化開發Spring提供了本身的緩存抽象,也定義了一些相似的註解,在實際開發中通常用Spring的緩存抽象。
二、Spring的緩存抽象
Spring框架自身並無實現緩存解決方案,可是從3.1開始定義了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口,提供對緩存功能的聲明,可以與多種流行的緩存實現集成。
幾個重要概念&緩存註解
緩存體驗
1.搭建基本環境(簡單的步驟這裏就不給代碼演示了)
1).建立department和employee表
2).建立javabean封裝數據(簡單java實體類)
3).整合mybatis操做數據庫
spring.datasource.url=jdbc:mysql://localhost:3306/spring_cache?useUnicode=true&characterEncoding=UTF8&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=123456 #驅動會根據url自行判斷 #spring.datasource.driver-class-name=com.mysql.jdbc.Driver #開啓駝峯命名匹配規則 mybatis.configuration.map-underscore-to-camel-case=true
2.緩存快速實現
1).開啓基於註解的緩存@EnableCaching
@MapperScan("com.wang.cache.mapper") @SpringBootApplication @EnableCaching //開啓基於註解的緩存 public class Springboot01CacheApplication { public static void main(String[] args) { SpringApplication.run(Springboot01CacheApplication.class, args); } }
2).給方法加上緩存標註
@Service public class EmpService { @Autowired EmployeeMapper employeeMapper; @Cacheable(cacheNames = {"emp"}) public Employee getEmp(Integer id){ return employeeMapper.getEmployeeById(id); } }
3).啓動項目測試,調用這個方法後,查看日誌是否打印,若只在第一次訪問的時候打印數據庫日誌,說明該結果已經被緩存了
@Cacheable屬性
cacheNames/value:指定緩存的名字,能夠指定將方法的結果放在哪一個緩存中,能夠是數組的方式指定多個緩存
key:緩存數據使用的key,能夠用它來指定,默認使用方法參數的值 1-方法的返回值 編寫SpEL #id 參數id的值 #a0 #p0 #root.args[0]
keyGenerator:key的生成器,能夠本身指定key的生成器的組件id(key與keyGenerator二選一使用)
/** * 緩存配置類 */ @Configuration public class MyCacheConfig { @Bean("myKeyGenerator") public KeyGenerator keyGenerator(){ return new KeyGenerator(){ @Override public Object generate(Object o, Method method, Object... objects) { return method.getName()+"["+Arrays.asList(objects) +"]"; } }; } }
@Cacheable(cacheNames = {"emp"},keyGenerator = "myKeyGenerator") public Employee getEmp(Integer id){ return employeeMapper.getEmployeeById(id); }
cacheManager:指定緩存管理器,或者指定緩存解析器(二選一)
condition:自定符合條件的狀況下才緩存
@Cacheable(cacheNames = {"emp"},keyGenerator = "myKeyGenerator",condition = "#id>1") public Employee getEmp(Integer id){ return employeeMapper.getEmployeeById(id); }
unless:否認緩存,當unless指定的條件爲true,方法的返回值不會緩存,能夠獲取到結果進行判斷(#result能夠取出結果)
@Cacheable(cacheNames = {"emp"},keyGenerator = "myKeyGenerator",unless = "#a0==2") public Employee getEmp(Integer id){ return employeeMapper.getEmployeeById(id); }
sync:是否使用異步模式
@CachePut
@Cacheable調用時機是在方法以前調用,若緩存中有了則調用緩存中的方法,若緩存中沒有則調用該方法。
@CachePut的調用時機是在方法以後調用,先調用目標方法,而後將目標方法的結果緩存起來,注意該註解標註後不管是怎麼樣都會調用目標方法
測試@CachePut緩存:
1). 查詢1號員工,查到的結果會放到緩存中
2). 查詢以前的結果,看看有沒有調用目標查詢方法,如沒有調用說明已經被緩存了
3). 更新1號員工
@CachePut(value = "emp") public Employee updateEmp(Employee employee){ System.out.println("updateEmp:"+employee); employeeMapper.updateEmployee(employee); return employee; }
4). 此時查詢員工發現查詢的是更新前的數據,緣由key默認是傳入的employee對象,而查詢的key是員工的id,1號員工沒有更新查詢的緩存,因此應該指定key,保證與查詢的key相同,下面有兩種指定key的方式:
1.key="#employee.id",使用傳入的參數的員工id
2.key="#result.id",使用返回後的id(@Cacheable沒法用result,由於是在方法運行以前調用的)
@CachePut(value = "emp",key="#result.id") public Employee updateEmp(Employee employee){ System.out.println("updateEmp:"+employee); employeeMapper.updateEmployee(employee); return employee; }
重複上述測試步驟,若查詢的結果是更新後的數據,而且沒有調用查詢員工的service方法,說明該註解起做用了,並且同時更新了數據與緩存。
@CacheEvict
屬性詳解
key :制定要清除的數據,默認傳入的參數爲key
allEntries = true,指定這個緩存中全部數據
beforeInvocation:緩存的清除默認是否在方法執行以前執行,默認緩存清除操做是在方法運行以後執行
beforeInvocation = true 表示清楚在方法執行以前執行,不管方法是否異常,都會執行清除
@CacheEvict(value = "emp",key="#id"/*,allEntries = true*//*,beforeInvocation = true*/) public void deleteEmp(Integer id){ System.out.println("delEmp"+id); //int i = 1/0; }
@Caching
使用該註解能夠配置多個緩存註解:
@Caching(
cacheable = {
@Cacheable(value = "emp",key="#lastName")
},
put = {
@CachePut(value = "emp",key="#result.id"), //將返回的員工id也放到緩存中
@CachePut(value = "emp",key="#result.email")
}
)
public Employee getEmpByLastName(String lastName){
return employeeMapper.getEmpByLastName(lastName);
}
@CacheConfig
該註解是在類上加的,主要做用是抽取緩存的公共配置,在這裏配置的緩存將做用於該類的全部方法。
@CacheConfig(cacheNames = "emp") //抽取緩存的公共配置 @Service public class EmpService { }