Spring新增對快取的支援
快取可以可以儲存經常使用到的資訊,如果這些資訊儲存在資料庫中,經常對資料庫的讀取會嚴重影響應用的效能,所以將這些資訊儲存在快取中,取出來就可以立即使用。
1、啟用spring對快取的支援
Spring對快取的支援有兩種方式:
1)註解驅動快取
2)XML申明的快取
使用Spring最通用的方法就是在方法上新增@Cacheable和@CacheEvict註解。本人更喜歡使用XML與註解混合使用的方式開發。
2、使用XML檔案配置快取
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd" >
<!-- 啟用快取註解開關 -->
<cache:annotation-driven cache-manager="cacheManager"/>
<!-- 啟用註解 -->
<context:component-scan base-package="com.zjp" />
<context:annotation-config/>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" >
<property name="configLocation" value="classpath:ehcache.xml"/>
</bean>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcache"/>
</bean>
</beans>
在spring配置檔案中聲明瞭使用ehcache快取管理器以及對應的ehcache.xml檔案定義的快取。
對應的ehcache.xml檔案
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<!-- 磁碟快取位置 -->
<diskStore path="java.io.tmpdir/ehcache"/>
<!-- 預設快取 -->
<defaultCache
maxEntriesLocalHeap="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxEntriesLocalDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</defaultCache>
<cache name="userCache"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="3"
timeToLiveSeconds="3"
maxEntriesLocalDisk="10000000"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU"/>
<cache name="users"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="3"
timeToLiveSeconds="3"
maxEntriesLocalDisk="10000000"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
其中定義了兩個快取,分別為userCache和users。
3、為對應的方法添加註解支援快取
為對應的方法新增上註解就可以實現對快取的控制,常用的註解如下:
註解 | 作用 |
---|---|
@Cacheable | 新增快取之前檢查快取中是否存在,存在就不呼叫,否則呼叫 |
@CachePut | 不管快取是否存在都呼叫方法 |
@CacheEvict | 刪除一條或者多條快取 |
@Caching | 分組的註解,可以同時應用多個快取註解 |
1)新增快取
@Cacheable和@CachePut註解都可以填充快取,但是它們的工作方差異。
@Cacheable首先在快取中查詢條目,如果找到了匹配的條目,那麼就不會對方法進行
了。如果沒有找到匹配的條目,方法會被呼叫並且返回值要放到快取之中。而@Cache
不會在快取中檢查匹配的值,目標方法總是會被呼叫,並將返回值新增到快取之中。
a、自定義快取key
@Cacheable和@CachePut都有一個名為key屬性,這個屬效能夠替換預設的key,它是通過
一個SpEL表示式計算得到的。任意的SpEL表示式都是可行的,但是更常見的場景是所定義的
表示式與儲存在快取中的值有關,據此計算得到key。
@CachePut(value = "users", key = "#user.getId()")
public void updateUser(User user) {
userDao.updateUser(user);
}
b、條件化快取
@Cacheable和@CachePut提供了兩個屬性用以實現條件化快取:unless和condition,
這兩個屬性都接受一個SpEL表示式。如果unless屬性的SpEL表示式計算結果為true,那麼
快取方法返回的資料就不會放到快取中。與之類似,如果condition屬性的SpEL表示式計算
結果為false,那麼對於這個方法快取就會被禁用掉。
@Cacheable(value = "users", condition = "#user.getId() <= 2")// 當id>2的時候禁用快取
public User findUserInLimit(User user) {
return userDao.findUserById(user.getId());
}
2)快取的移除
使用@CacheEvict 就可以移除快取中對應的資料。
對於快取操作的UserService如下:
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Cacheable({"users"})
public User findUser(User user) {
System.out.println("userDao--"+userDao);
User findUserById = userDao.findUserById(user.getId());//資料庫
System.out.println("user---"+findUserById);
return userDao.findUserById(user.getId());//資料庫
}
@Cacheable(value = "users", condition = "#user.getId() <= 2")// 當id>2的時候禁用快取
public User findUserInLimit(User user) {
return userDao.findUserById(user.getId());
}
@CachePut(value = "users", key = "#user.getId()")
public void updateUser(User user) {
userDao.updateUser(user);
}
@CacheEvict(value = "users")
public void removeUser(User user) {
userDao.removeUserById(user.getId());
}
@CacheEvict(value = "users", allEntries = true)
public void clear() {
userDao.removeAllUser();
}
}
同時新增上其他的
public interface UserDao {
/**
* 刪除所有使用者
*/
public void removeAllUser();
/**
* 根據Id查詢使用者
* @param id
* @return
*/
public User findUserById(long id);
/**
* 更新使用者
* @param user
*/
public void updateUser(User user);
/**
* 根據Id刪除使用者
* @param id
*/
public void removeUserById(long id);
}
package com.zjp.service.impl;
import org.springframework.stereotype.Service;
import com.zjp.domain.User;
import com.zjp.service.UserDao;
@Service
public class UserDaoImpl implements UserDao{
public void removeAllUser() {
// TODO Auto-generated method stub
}
public User findUserById(long id) {
User user = new User();
user.setId(123424);
user.setPassword("ahfakjbnfjk");
user.setUsername("lisi");
return user;
}
public void updateUser(User user) {
// TODO Auto-generated method stub
}
public void removeUserById(long id) {
// TODO Auto-generated method stub
}
}