spring-data-redis 項目,配合 spring 特性並集成 Jedis 的一些命令和方法。
配置redis繼承到spring管理項目,使用注解實現redis緩存功能。
參考:http://www.cnblogs.com/java-class/p/7112541.html
步驟:1.maven的pom.xml文件導入架包
2.配置文件添加配置
3.spring管理bean的生成,xml文件配置
4. RedisCacheConfig redis自定義的工具類,自定義redis的key生成規則
5.在你想要做緩存的地方,使用注解進行緩存
1.maven的pom.xml文件導入架包【本來spring-data-redis架包版本使用最新的2.0.0 ,甚至使用到1.8.4版本,只要保存,啟動項目,spring管理的bean都會創建失敗,架包沖突的緣故或者其他問題,所以退而求其次,使用1.6.2版本】
<!-- redis架包 --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.6.2.RELEASE</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
2.配置文件添加配置
#============================# #==== Redis settings ====# #============================# #redis 服務器 IP redis.host=127.0.0.1 #redis 服務器端口 redis.port=6379 #redis 密碼 redis.pass=398023 #redis 支持16個數據庫(相當於不同用戶)可以使不同的應用程序數據彼此分開同時又存儲在相同的實例上 redis.dbIndex=0 #redis 緩存數據過期時間單位秒 redis.expiration=3000 #控制一個 pool 最多有多少個狀態為 idle 的jedis實例 redis.maxIdle=300 #控制一個 pool 可分配多少個jedis實例 redis.maxActive=600 #當borrow一個jedis實例時,最大的等待時間,如果超過等待時間,則直接拋出JedisConnectionException; redis.maxWait=1000 #在borrow一個jedis實例時,是否提前進行alidate操作;如果為true,則得到的jedis實例均是可用的; redis.testOnBorrow=true
3.spring管理bean的生成,xml文件配置
<!-- **************************************************redis********************************************************** -->
<!-- 配置 JedisPoolConfig 實例 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}"/>
<property name="maxTotal" value="${redis.maxActive}"/>
<property name="maxWaitMillis" value="${redis.maxWait}"/>
<property name="testOnBorrow" value="${redis.testOnBorrow}"/>
</bean>
<!-- 配置JedisConnectionFactory -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.host}"/>
<property name="port" value="${redis.port}"/>
<property name="password" value="${redis.pass}"/>
<property name="database" value="${redis.dbIndex}"/>
<property name="poolConfig" ref="poolConfig"/>
</bean>
<!-- 配置RedisTemplate -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
</bean>
<!-- 配置RedisCacheManager -->
<bean id="redisCacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
<constructor-arg name="redisOperations" ref="redisTemplate"/>
<property name="defaultExpiration" value="${redis.expiration}"/>
</bean>
<!-- 配置RedisCacheConfig -->
<bean id="redisCacheConfig" class="com.sxd.util.RedisCacheConfig">
<constructor-arg ref="jedisConnectionFactory"/>
<constructor-arg ref="redisTemplate"/>
<constructor-arg ref="redisCacheManager"/>
</bean>
JedisPoolConfig jedis連接池配置對象
JedisConnectionFactory jedis連接工廠,生成連接對象
RedisTemplate RedisTemplate 對 RedisConnection 進行了封裝。提供連接管理,序列化等功能,它對 Redis 的交互進行了更高層次的抽象,極大的方便和簡化了 Redis 的操作
RedisCacheManager 做為 redis 統一的調度和管理者
RedisCacheConfig RedisCacheConfig extends org.springframework.cache.annotation.CachingConfigurerSupport,自定義redis的key生成規則,如果不在注解參數中注明key=“”的話,就采用這個類中的key生成規則生成key
4. RedisCacheConfig redis自定義的工具類,自定義redis的key生成規則
package com.sxd.util; import java.lang.reflect.Method; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; @Configuration @EnableCaching public class RedisCacheConfig extends CachingConfigurerSupport { protected final static Logger log = LoggerFactory.getLogger(RedisCacheConfig.class); private volatile JedisConnectionFactory mJedisConnectionFactory; private volatile RedisTemplate<String, String> mRedisTemplate; private volatile RedisCacheManager mRedisCacheManager; public RedisCacheConfig() { super(); } public RedisCacheConfig(JedisConnectionFactory mJedisConnectionFactory, RedisTemplate<String, String> mRedisTemplate, RedisCacheManager mRedisCacheManager) { super(); this.mJedisConnectionFactory = mJedisConnectionFactory; this.mRedisTemplate = mRedisTemplate; this.mRedisCacheManager = mRedisCacheManager; } public JedisConnectionFactory redisConnectionFactory() { return mJedisConnectionFactory; } public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) { return mRedisTemplate; } public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate) { return mRedisCacheManager; } @Bean public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { //規定 本類名+方法名+參數名 為key StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()+"_"); sb.append(method.getName()+"_"); for (Object obj : params) { sb.append(obj.toString()+","); } return sb.toString(); } }; } }
5.在你想要做緩存的地方,使用注解進行緩存
先介紹幾個注解
1》@CacheConfig 配置在類上,cacheNames即定義了本類中所有用到緩存的地方,都去找這個庫。只要使用了這個注解,在方法上@Cacheable @CachePut @CacheEvict就可以不用寫value去找具體庫名了。【一般不怎么用】
2》@Cacheable 配置在方法或類上,作用:本方法執行后,先去緩存看有沒有數據,如果沒有,從數據庫中查找出來,給緩存中存一份,返回結果,下次本方法執行,在緩存未過期情況下,先在緩存中查找,有的話直接返回,沒有的話從數據庫查找
3》@CachePut 類似於更新操作,即每次不管緩存中有沒有結果,都從數據庫查找結果,並將結果更新到緩存,並返回結果
4》@CacheEvict 用來清除用在本方法或者類上的緩存數據(用在哪里清除哪里)
例子:

最直觀的表現:首次登錄,會有一條數據庫的查詢語句在控制台。
退出再登錄,不會執行數據庫的查詢,直接從數據庫中取出緩存,登錄成功。
說明:
①使用了@Cacheable(value="myUser"),即表示緩存中有,直接從緩存取出,沒有的話先從數據庫中查出,然后再插入
②如果未在類上使用@CacheConfig注解規定數據要緩存到哪個庫中,就必須給value一個值,規定數據最后緩存到哪個redis庫中
③因為redis緩存數據實際就是鍵值對的形式存儲,因此必須給定key-value的key,這里沒有給key參數賦值,所以key的生成規則按照上面工具類中規定的key生成的
④key-value的value就是本方法的返回值,如果要緩存登錄用戶信息,本方法需要進行修改,返回user對象就可以緩存到key-value的value中
*******************************************************************************************************************************************************************
*******************************************************************************************************************************************************************
查看一下本次緩存的數據,在redis可視化工具中
myUser是上面注解中的value,也就是緩存數據庫名字叫myUser
鍵名key為:\xAC\xED\x00\x05t\x00Jcom.sxd.controller.WelcomeController_welcome_com.sxd.entity.User@36e69d03,
鍵值對value值:\xAC\xED\x00\x05t\x00\x07success

①redis以鍵值對的形式存儲緩存數據,而且會對對象進行序列化,如上圖可以看到,鍵和值前面都有一串序列化的字符
② RedisTemplate默認采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。JdkSerializationRedisSerializer
③SDR默認采用的序列化策略有兩種,一種是String的序列化策略,一種是JDK的序列化策略。
StringRedisTemplate默認采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。StringRedisSerializer
RedisTemplate默認采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。JdkSerializationRedisSerializer
就是因為序列化策略的不同,即使是同一個key用不同的Template去序列化,結果是不同的。所以根據key去刪除數據的時候就出現了刪除失敗的問題。
④在上面配置文件中,沒有顯式的給出序列化策略,會有默認的序列化策略。
⑤如果因為序列化策略不同,可以區顯式的設置 具體可參考:http://blog.csdn.net/y666666y/article/details/70212767
<!-- redis 序列化策略 ,通常情況下key值采用String序列化策略, --> <!-- 如果不指定序列化策略,StringRedisTemplate的key和value都將采用String序列化策略; --> <!-- 但是RedisTemplate的key和value都將采用JDK序列化 這樣就會出現采用不同template保存的數據不能用同一個template刪除的問題 --> <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer" /> <bean id='redisWriteTemplate' class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisWriteConnectionFactory" /> <property name="keySerializer" ref="stringRedisSerializer" /> <property name="hashKeySerializer" ref="stringRedisSerializer" /> </bean>
*************************************************************************************************************************************************************************************
*************************************************************************************************************************************************************************************
最后給出這幾個注解的具體參數以及使用相關配圖參考。
參考自:http://blog.csdn.net/sanjay_f/article/details/47372967
表 1. @Cacheable 作用和配置方法
@Cacheable 的作用 主要針對方法配置,能夠根據方法的請求參數對其結果進行緩存
表 2. @CachePut 作用和配置方法
@CachePut 的作用 主要針對方法配置,能夠根據方法的請求參數對其結果進行緩存,和 @Cacheable 不同的是,它每次都會觸發真實方法的調用
| @CachePut 主要的參數 | ||
| value | 緩存的名稱,在 spring 配置文件中定義,必須指定至少一個 | 例如: @Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”} |
| key | 緩存的 key,可以為空,如果指定要按照 SpEL 表達式編寫,如果不指定,則缺省按照方法的所有參數進行組合 | 例如: @Cacheable(value=”testcache”,key=”#userName”) |
| condition | 緩存的條件,可以為空,使用 SpEL 編寫,返回 true 或者 false,只有為 true 才進行緩存 | 例如: @Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
表 3. @CacheEvict 作用和配置方法
@CachEvict 的作用 主要針對方法配置,能夠根據一定的條件對緩存進行清空| @CacheEvict 主要的參數 | ||
| value | 緩存的名稱,在 spring 配置文件中定義,必須指定至少一個 | 例如: @CachEvict(value=”mycache”) 或者 @CachEvict(value={”cache1”,”cache2”} |
| key | 緩存的 key,可以為空,如果指定要按照 SpEL 表達式編寫,如果不指定,則缺省按照方法的所有參數進行組合 | 例如: @CachEvict(value=”testcache”,key=”#userName”) |
| condition | 緩存的條件,可以為空,使用 SpEL 編寫,返回 true 或者 false,只有為 true 才清空緩存 | 例如: @CachEvict(value=”testcache”, condition=”#userName.length()>2”) |
| allEntries | 是否清空所有緩存內容,缺省為 false,如果指定為 true,則方法調用后將立即清空所有緩存 | 例如: @CachEvict(value=”testcache”,allEntries=true) |
| beforeInvocation | 是否在方法執行前就清空,缺省為 false,如果指定為 true,則在方法還沒有執行的時候就清空緩存,缺省情況下,如果方法執行拋出異常,則不會清空緩存 | 例如: @CachEvict(value=”testcache”,beforeInvocation=true) |
*************************************************************************************************************************************************************************************
*************************************************************************************************************************************************************************************
spEL表達式的使用方法:http://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/expressions.html
關於注解實現Redis緩存的方法,只有將key設計的合理且強大,整個的緩存在項目中才能通用且高效。否則,就像我上面的簡單的例子一樣,真的是搞笑了。
