SpringBoot之資料快取Cache操作
一、前言
快取要解決的問題:一個程式的瓶頸在於資料庫,我們也知道記憶體的速度是大大快於硬碟的速度的。當我們需要重複地獲取相同的資料的時候,我們一次又一次的請求資料庫或者遠端服務,導致大量的時間耗費在資料庫查詢或者遠端方法呼叫上,導致程式效能的惡化,這便是資料快取要解決的問題。
類似的快取技術有:Redis、EhCache、Guava等,現在一般常用的為Redis。
Spring 3.1 引入了激動人心的基於註釋(annotation)的快取(cache)技術,它本質上不是一個具體的快取實現方案(例如EHCache 或者 OSCache),而是一個對快取使用的抽象,通過在既有程式碼中新增少量它定義的各種 annotation,即能夠達到快取方法的返回物件的效果。
Spring 的快取技術還具備相當的靈活性,不僅能夠使用 SpEL(Spring Expression Language)來定義快取的 key 和各種 condition,還提供開箱即用的快取臨時儲存方案,也支援和主流的專業快取例如 EHCache 整合。
其特點總結如下:
1. 通過少量的配置 annotation 註釋即可使得既有程式碼支援快取
2. 支援開箱即用 Out-Of-The-Box,即不用安裝和部署額外第三方元件即可使用快取
3. 支援 Spring Express Language,能使用物件的任何屬性或者方法來定義快取的 key 和 condition
4. 支援 AspectJ,並通過其實現任何方法的快取支援
5. 支援自定義 key 和自定義快取管理者,具有相當的靈活性和擴充套件性
二、Spring快取支援
Spring定義了org.springframework.cache.CacheManager和org.springframework.cache.Cache介面用來統一不同的快取的技術。其中,CacheManager是Spring提供的各種快取技術抽象介面,Cache介面包含快取的各種操作(增加、刪除、獲得快取,我們一般不會直接和此介面打交道)。
1..Spring支援的CacheManager實現如下圖:
在我們使用任意一個實現的CacheManager的時候,需註冊實現的CacheManager的Bean,例如:
@Bean public EhCacheCacheManager cacheManager(CacheManager ehCacheCacheManager) { return new EhCacheCacheManager(ehCacheCacheManager); }
2.聲名式快取註解
Spring提供了4個註解來宣告快取規則(又是使用註解式的AOP的一個生動例子)。這四個註解如表8-6
所示。
@Cacheable、@CachePut、@CacheEvit都有value屬性,指定的是要使用的快取名稱;key屬性指定的是
資料在快取中的儲存的鍵。
3.開啟聲名式快取支援
開啟聲名式快取支援十分簡單,只需在配置類上使用@EnableCaching註解即可,例如:
@Configuration
@EnableCaching
public class AppConfig {
}
四:本例
將以Spring Boot預設的ConcurrentMapCacheManager作為快取技術,演示@Cacheable、CachePut、@CacheEvit,最後使用EhCache、Guava來替換快取技術。
1.pom.xml,主要是需要加入jpa和mysql。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
2.application.yml,進行mysql配置和jpa配置,注意這裡的show-sql: true
server:
port: 5000
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
username: root
password: ******
jpa:
hibernate:
ddl-auto: update
show-sql: true
3.以userinfo為例進行配置
//UserInfo
@Entity
public class UserInfo {
@Id
@GeneratedValue
private Long id;
private String name;
private int age;
private String sex;
private String address;
省略get/set...
}
//UserInfoDao
public interface UserInfoDao extends JpaRepository<UserInfo, Long> {
//
}
//UserInfoService
public interface UserInfoService {
UserInfo save(UserInfo userInfo);
void remove(Long id);
UserInfo findOne(UserInfo userInfo);
}
//UserInfoServiceImpl
@Service
public class UserInfoServiceImpl implements UserInfoService {
private static Logger log = LoggerFactory.getLogger(UserInfoServiceImpl.class);
@Autowired
UserInfoDao userInfoDao;
@Override
@CachePut(value = "userinfocache",key="#userInfo.id") //@CachePut快取新增的或更新的資料到快取,其中快取名稱為people,資料的key是person的id。
public UserInfo save(UserInfo userInfo) {
UserInfo u = userInfoDao.save(userInfo);
log.info("為userinfo的id(也是cache的key):" + u.getId() + "資料做了快取");
return u;
}
@Override
@CacheEvict(value = "userinfocache") //@CacheEvict從快取people中刪除key為id的資料。
public void remove(Long id) {
log.info("刪除了userinfo的id(也是cache的key):" + id + "資料快取");
userInfoDao.delete(id);
}
@Override
@Cacheable(value = "userinfocache",key="#userInfo.id") //@Cacheable快取key為person的id資料到快取people中。
public UserInfo findOne(UserInfo userInfo) {
UserInfo u = userInfoDao.findOne(userInfo.getId());
log.info("為userinfo的id(也是cache的key):" + u.getId() + "資料做了快取");
return u;
}
}
//UserCacheController
@RestController
@RequestMapping("/userinfo")
public class UserCacheController {
@Autowired
UserInfoService userInfoService;
@RequestMapping("/put")
public UserInfo put(UserInfo userInfo){
return userInfoService.save(userInfo);
}
@RequestMapping("/remove")
public String remove(Long id){
userInfoService.remove(id);
return "success";
}
@RequestMapping("/cache")
public UserInfo findone(UserInfo userInfo){
return userInfoService.findOne(userInfo);
}
}
//別忘了,啟動類中加上@EnableCaching
@SpringBootApplication
@EnableCaching
public class SpringbootcacheApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootcacheApplication.class, args);
}
}