日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Redis整合Spring结合使用缓存实例(转)

發(fā)布時間:2025/3/21 javascript 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis整合Spring结合使用缓存实例(转) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

? ? ? ? ?林炳文Evankaka原創(chuàng)作品。轉(zhuǎn)載請注明出處http://blog.csdn.net/evankaka

? ? ? ? ?摘要:本文介紹了如何在Spring中配置redis,并通過Spring中AOP的思想,將緩存的方法切入到有需要進入緩存的類或方法前面。

一、Redis介紹

什么是Redis?

? ? ? redis是一個key-value存儲系統(tǒng)。和Memcached類似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。這些數(shù)據(jù)類型都支持push/pop、add/remove及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎(chǔ)上,redis支持各種不同方式的排序。與memcached一樣,為了保證效率,數(shù)據(jù)都是緩存在內(nèi)存中。區(qū)別的是redis會周期性的把更新的數(shù)據(jù)寫入磁盤或者把修改操作寫入追加的記錄文件,并且在此基礎(chǔ)上實現(xiàn)了master-slave(主從)同步。

它有什么特點?

(1)Redis數(shù)據(jù)庫完全在內(nèi)存中,使用磁盤僅用于持久性。
(2)相比許多鍵值數(shù)據(jù)存儲,Redis擁有一套較為豐富的數(shù)據(jù)類型。
(3)Redis可以將數(shù)據(jù)復(fù)制到任意數(shù)量的從服務(wù)器。

Redis 優(yōu)勢?
?(1)異常快速:Redis的速度非常快,每秒能執(zhí)行約11萬集合,每秒約81000+條記錄。
?(2)支持豐富的數(shù)據(jù)類型:Redis支持最大多數(shù)開發(fā)人員已經(jīng)知道像列表,集合,有序集合,散列數(shù)據(jù)類型。這使得它非常容易解決各種各樣的問題,因為我們知道哪些問題是可以處理通過它的數(shù)據(jù)類型更好。
(3)操作都是原子性:所有Redis操作是原子的,這保證了如果兩個客戶端同時訪問的Redis服務(wù)器將獲得更新后的值。
(4)多功能實用工具:Redis是一個多實用的工具,可以在多個用例如緩存,消息,隊列使用(Redis原生支持發(fā)布/訂閱),任何短暫的數(shù)據(jù),應(yīng)用程序,如Web應(yīng)用程序會話,網(wǎng)頁命中計數(shù)等。

Redis 缺點?

(1)單線程

(2)耗內(nèi)存

二、使用實例

本文使用maven+eclipse+sping

1、引入jar包

?

[html]?view plain?copy
  • ????<!--Redis?start?-->??
  • <dependency>??
  • ????<groupId>org.springframework.data</groupId>??
  • ????<artifactId>spring-data-redis</artifactId>??
  • ????<version>1.6.1.RELEASE</version>??
  • </dependency>??
  • <dependency>??
  • ????<groupId>redis.clients</groupId>??
  • ????<artifactId>jedis</artifactId>??
  • ????<version>2.7.3</version>??
  • </dependency>??
  • ???<!--Redis?end?-->??

  • 2、配置bean

    ?

    在application.xml加入如下配置

    ?

    [html]?view plain?copy
  • <!--?jedis?配置?-->??
  • ???<bean?id="poolConfig"?class="redis.clients.jedis.JedisPoolConfig"?>??
  • ?????????<property?name="maxIdle"?value="${redis.maxIdle}"?/>??
  • ?????????<property?name="maxWaitMillis"?value="${redis.maxWait}"?/>??
  • ?????????<property?name="testOnBorrow"?value="${redis.testOnBorrow}"?/>??
  • ???</bean?>??
  • ??<!--?redis服務(wù)器中心?-->??
  • ???<bean?id="connectionFactory"??class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"?>??
  • ?????????<property?name="poolConfig"?ref="poolConfig"?/>??
  • ?????????<property?name="port"?value="${redis.port}"?/>??
  • ?????????<property?name="hostName"?value="${redis.host}"?/>??
  • ?????????<property?name="password"?value="${redis.password}"?/>??
  • ?????????<property?name="timeout"?value="${redis.timeout}"?></property>??
  • ???</bean?>??
  • ???<bean?id="redisTemplate"?class="org.springframework.data.redis.core.RedisTemplate"?>??
  • ?????????<property?name="connectionFactory"?ref="connectionFactory"?/>??
  • ?????????<property?name="keySerializer"?>??
  • ?????????????<bean?class="org.springframework.data.redis.serializer.StringRedisSerializer"?/>??
  • ?????????</property>??
  • ?????????<property?name="valueSerializer"?>??
  • ?????????????<bean?class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"?/>??
  • ?????????</property>??
  • ???</bean?>??
  • ?????
  • ????<!--?cache配置?-->??
  • ???<bean?id="methodCacheInterceptor"?class="com.mucfc.msm.common.MethodCacheInterceptor"?>??
  • ?????????<property?name="redisUtil"?ref="redisUtil"?/>??
  • ???</bean?>??
  • ???<bean?id="redisUtil"?class="com.mucfc.msm.common.RedisUtil"?>??
  • ?????????<property?name="redisTemplate"?ref="redisTemplate"?/>??
  • ???</bean?>??

  • 其中配置文件redis一些配置數(shù)據(jù)redis.properties如下:

    ?

    ?

    [plain]?view plain?copy
  • #redis中心??
  • redis.host=10.75.202.11??
  • redis.port=6379??
  • redis.password=123456??
  • redis.maxIdle=100??
  • redis.maxActive=300??
  • redis.maxWait=1000??
  • redis.testOnBorrow=true??
  • redis.timeout=100000??
  • ??
  • #?不需要加入緩存的類??
  • targetNames=xxxRecordManager,xxxSetRecordManager,xxxStatisticsIdentificationManager??
  • #?不需要緩存的方法??
  • methodNames=??
  • ??
  • #設(shè)置緩存失效時間??
  • com.service.impl.xxxRecordManager=?60??
  • com.service.impl.xxxSetRecordManager=?60??
  • defaultCacheExpireTime=3600??
  • ??
  • fep.local.cache.capacity?=10000??

  • 要掃這些properties文件,在application.xml加入如下配置

    ?

    ?

    [plain]?view plain?copy
  • ?<!--?引入properties配置文件?-->????
  • ?<bean?id="propertyConfigurer"?class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">??
  • ????<property?name="locations">??
  • ????????<list>??
  • ???????????<value>classpath:properties/*.properties</value>??
  • ????????????<!--要是有多個配置文件,只需在這里繼續(xù)添加即可?-->??
  • ????????</list>??
  • ????</property>??
  • </bean>??
  • 3、一些工具類

    (1)RedisUtil

    上面的bean中,RedisUtil是用來緩存和去除數(shù)據(jù)的實例

    ?

    [java]?view plain?copy
  • package?com.mucfc.msm.common;??
  • ??
  • import?java.io.Serializable;??
  • import?java.util.Set;??
  • import?java.util.concurrent.TimeUnit;??
  • ??
  • import?org.apache.log4j.Logger;??
  • import?org.springframework.data.redis.core.RedisTemplate;??
  • import?org.springframework.data.redis.core.ValueOperations;??
  • ??
  • /**?
  • ?*?redis?cache?工具類?
  • ?*??
  • ?*/??
  • public?final?class?RedisUtil?{??
  • ????private?Logger?logger?=?Logger.getLogger(RedisUtil.class);??
  • ????private?RedisTemplate<Serializable,?Object>?redisTemplate;??
  • ??
  • ????/**?
  • ?????*?批量刪除對應(yīng)的value?
  • ?????*??
  • ?????*?@param?keys?
  • ?????*/??
  • ????public?void?remove(final?String...?keys)?{??
  • ????????for?(String?key?:?keys)?{??
  • ????????????remove(key);??
  • ????????}??
  • ????}??
  • ??
  • ????/**?
  • ?????*?批量刪除key?
  • ?????*??
  • ?????*?@param?pattern?
  • ?????*/??
  • ????public?void?removePattern(final?String?pattern)?{??
  • ????????Set<Serializable>?keys?=?redisTemplate.keys(pattern);??
  • ????????if?(keys.size()?>?0)??
  • ????????????redisTemplate.delete(keys);??
  • ????}??
  • ??
  • ????/**?
  • ?????*?刪除對應(yīng)的value?
  • ?????*??
  • ?????*?@param?key?
  • ?????*/??
  • ????public?void?remove(final?String?key)?{??
  • ????????if?(exists(key))?{??
  • ????????????redisTemplate.delete(key);??
  • ????????}??
  • ????}??
  • ??
  • ????/**?
  • ?????*?判斷緩存中是否有對應(yīng)的value?
  • ?????*??
  • ?????*?@param?key?
  • ?????*?@return?
  • ?????*/??
  • ????public?boolean?exists(final?String?key)?{??
  • ????????return?redisTemplate.hasKey(key);??
  • ????}??
  • ??
  • ????/**?
  • ?????*?讀取緩存?
  • ?????*??
  • ?????*?@param?key?
  • ?????*?@return?
  • ?????*/??
  • ????public?Object?get(final?String?key)?{??
  • ????????Object?result?=?null;??
  • ????????ValueOperations<Serializable,?Object>?operations?=?redisTemplate??
  • ????????????????.opsForValue();??
  • ????????result?=?operations.get(key);??
  • ????????return?result;??
  • ????}??
  • ??
  • ????/**?
  • ?????*?寫入緩存?
  • ?????*??
  • ?????*?@param?key?
  • ?????*?@param?value?
  • ?????*?@return?
  • ?????*/??
  • ????public?boolean?set(final?String?key,?Object?value)?{??
  • ????????boolean?result?=?false;??
  • ????????try?{??
  • ????????????ValueOperations<Serializable,?Object>?operations?=?redisTemplate??
  • ????????????????????.opsForValue();??
  • ????????????operations.set(key,?value);??
  • ????????????result?=?true;??
  • ????????}?catch?(Exception?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}??
  • ????????return?result;??
  • ????}??
  • ??
  • ????/**?
  • ?????*?寫入緩存?
  • ?????*??
  • ?????*?@param?key?
  • ?????*?@param?value?
  • ?????*?@return?
  • ?????*/??
  • ????public?boolean?set(final?String?key,?Object?value,?Long?expireTime)?{??
  • ????????boolean?result?=?false;??
  • ????????try?{??
  • ????????????ValueOperations<Serializable,?Object>?operations?=?redisTemplate??
  • ????????????????????.opsForValue();??
  • ????????????operations.set(key,?value);??
  • ????????????redisTemplate.expire(key,?expireTime,?TimeUnit.SECONDS);??
  • ????????????result?=?true;??
  • ????????}?catch?(Exception?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}??
  • ????????return?result;??
  • ????}??
  • ??
  • ????public?void?setRedisTemplate(??
  • ????????????RedisTemplate<Serializable,?Object>?redisTemplate)?{??
  • ????????this.redisTemplate?=?redisTemplate;??
  • ????}??
  • }??
  • (2)MethodCacheInterceptor

    ?

    切面MethodCacheInterceptor,這是用來給不同的方法來加入判斷如果緩存存在數(shù)據(jù),從緩存取數(shù)據(jù)。否則第一次從數(shù)據(jù)庫取,并將結(jié)果保存到緩存 中去。

    ?

    [java]?view plain?copy
  • package?com.mucfc.msm.common;??
  • ??
  • import?java.io.File;??
  • import?java.io.FileInputStream;??
  • import?java.io.InputStream;??
  • import?java.util.ArrayList;??
  • import?java.util.List;??
  • import?java.util.Properties;??
  • ??
  • import?org.aopalliance.intercept.MethodInterceptor;??
  • import?org.aopalliance.intercept.MethodInvocation;??
  • import?org.apache.log4j.Logger;??
  • ??
  • ??
  • public?class?MethodCacheInterceptor?implements?MethodInterceptor?{??
  • ????private?Logger?logger?=?Logger.getLogger(MethodCacheInterceptor.class);??
  • ????private?RedisUtil?redisUtil;??
  • ????private?List<String>?targetNamesList;?//?不加入緩存的service名稱??
  • ????private?List<String>?methodNamesList;?//?不加入緩存的方法名稱??
  • ????private?Long?defaultCacheExpireTime;?//?緩存默認的過期時間??
  • ????private?Long?xxxRecordManagerTime;?//??
  • ????private?Long?xxxSetRecordManagerTime;?//??
  • ??
  • ????/**?
  • ?????*?初始化讀取不需要加入緩存的類名和方法名稱?
  • ?????*/??
  • ????public?MethodCacheInterceptor()?{??
  • ????????try?{??
  • ?????????????File?f?=?new?File("D:\\lunaJee-workspace\\msm\\msm_core\\src\\main\\java\\com\\mucfc\\msm\\common\\cacheConf.properties");???
  • ?????????????//配置文件位置直接被寫死,有需要自己修改下??
  • ?????????????InputStream?in?=?new?FileInputStream(f);???
  • //??????????InputStream?in?=?getClass().getClassLoader().getResourceAsStream(??
  • //??????????????????"D:\\lunaJee-workspace\\msm\\msm_core\\src\\main\\java\\com\\mucfc\\msm\\common\\cacheConf.properties");??
  • ????????????Properties?p?=?new?Properties();??
  • ????????????p.load(in);??
  • ????????????//?分割字符串??
  • ????????????String[]?targetNames?=?p.getProperty("targetNames").split(",");??
  • ????????????String[]?methodNames?=?p.getProperty("methodNames").split(",");??
  • ??
  • ????????????//?加載過期時間設(shè)置??
  • ????????????defaultCacheExpireTime?=?Long.valueOf(p.getProperty("defaultCacheExpireTime"));??
  • ????????????xxxRecordManagerTime?=?Long.valueOf(p.getProperty("com.service.impl.xxxRecordManager"));??
  • ????????????xxxSetRecordManagerTime?=?Long.valueOf(p.getProperty("com.service.impl.xxxSetRecordManager"));??
  • ????????????//?創(chuàng)建list??
  • ????????????targetNamesList?=?new?ArrayList<String>(targetNames.length);??
  • ????????????methodNamesList?=?new?ArrayList<String>(methodNames.length);??
  • ????????????Integer?maxLen?=?targetNames.length?>?methodNames.length???targetNames.length??
  • ????????????????????:?methodNames.length;??
  • ????????????//?將不需要緩存的類名和方法名添加到list中??
  • ????????????for?(int?i?=?0;?i?<?maxLen;?i++)?{??
  • ????????????????if?(i?<?targetNames.length)?{??
  • ????????????????????targetNamesList.add(targetNames[i]);??
  • ????????????????}??
  • ????????????????if?(i?<?methodNames.length)?{??
  • ????????????????????methodNamesList.add(methodNames[i]);??
  • ????????????????}??
  • ????????????}??
  • ????????}?catch?(Exception?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}??
  • ????}??
  • ??
  • ????@Override??
  • ????public?Object?invoke(MethodInvocation?invocation)?throws?Throwable?{??
  • ????????Object?value?=?null;??
  • ??
  • ????????String?targetName?=?invocation.getThis().getClass().getName();??
  • ????????String?methodName?=?invocation.getMethod().getName();??
  • ????????//?不需要緩存的內(nèi)容??
  • ????????//if?(!isAddCache(StringUtil.subStrForLastDot(targetName),?methodName))?{??
  • ????????if?(!isAddCache(targetName,?methodName))?{??
  • ????????????//?執(zhí)行方法返回結(jié)果??
  • ????????????return?invocation.proceed();??
  • ????????}??
  • ????????Object[]?arguments?=?invocation.getArguments();??
  • ????????String?key?=?getCacheKey(targetName,?methodName,?arguments);??
  • ????????System.out.println(key);??
  • ??
  • ????????try?{??
  • ????????????//?判斷是否有緩存??
  • ????????????if?(redisUtil.exists(key))?{??
  • ????????????????return?redisUtil.get(key);??
  • ????????????}??
  • ????????????//?寫入緩存??
  • ????????????value?=?invocation.proceed();??
  • ????????????if?(value?!=?null)?{??
  • ????????????????final?String?tkey?=?key;??
  • ????????????????final?Object?tvalue?=?value;??
  • ????????????????new?Thread(new?Runnable()?{??
  • ????????????????????@Override??
  • ????????????????????public?void?run()?{??
  • ????????????????????????if?(tkey.startsWith("com.service.impl.xxxRecordManager"))?{??
  • ????????????????????????????redisUtil.set(tkey,?tvalue,?xxxRecordManagerTime);??
  • ????????????????????????}?else?if?(tkey.startsWith("com.service.impl.xxxSetRecordManager"))?{??
  • ????????????????????????????redisUtil.set(tkey,?tvalue,?xxxSetRecordManagerTime);??
  • ????????????????????????}?else?{??
  • ????????????????????????????redisUtil.set(tkey,?tvalue,?defaultCacheExpireTime);??
  • ????????????????????????}??
  • ????????????????????}??
  • ????????????????}).start();??
  • ????????????}??
  • ????????}?catch?(Exception?e)?{??
  • ????????????e.printStackTrace();??
  • ????????????if?(value?==?null)?{??
  • ????????????????return?invocation.proceed();??
  • ????????????}??
  • ????????}??
  • ????????return?value;??
  • ????}??
  • ??
  • ????/**?
  • ?????*?是否加入緩存?
  • ?????*??
  • ?????*?@return?
  • ?????*/??
  • ????private?boolean?isAddCache(String?targetName,?String?methodName)?{??
  • ????????boolean?flag?=?true;??
  • ????????if?(targetNamesList.contains(targetName)??
  • ????????????????||?methodNamesList.contains(methodName))?{??
  • ????????????flag?=?false;??
  • ????????}??
  • ????????return?flag;??
  • ????}??
  • ??
  • ????/**?
  • ?????*?創(chuàng)建緩存key?
  • ?????*?
  • ?????*?@param?targetName?
  • ?????*?@param?methodName?
  • ?????*?@param?arguments?
  • ?????*/??
  • ????private?String?getCacheKey(String?targetName,?String?methodName,??
  • ????????????Object[]?arguments)?{??
  • ????????StringBuffer?sbu?=?new?StringBuffer();??
  • ????????sbu.append(targetName).append("_").append(methodName);??
  • ????????if?((arguments?!=?null)?&&?(arguments.length?!=?0))?{??
  • ????????????for?(int?i?=?0;?i?<?arguments.length;?i++)?{??
  • ????????????????sbu.append("_").append(arguments[i]);??
  • ????????????}??
  • ????????}??
  • ????????return?sbu.toString();??
  • ????}??
  • ??
  • ????public?void?setRedisUtil(RedisUtil?redisUtil)?{??
  • ????????this.redisUtil?=?redisUtil;??
  • ????}??
  • }??

  • 4、配置需要緩存的類或方法

    ?

    在application.xml加入如下配置,有多個類或方法可以配置多個

    ?

    [html]?view plain?copy
  • <!--?需要加入緩存的類或方法?-->??
  • <bean?id="methodCachePointCut"??class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"?>??
  • ??????<property?name="advice"?>??
  • ??????????<ref?local="methodCacheInterceptor"?/>??
  • ??????</property>??
  • ??????<property?name="patterns"?>??
  • ??????????<list>??
  • ???????????<!--?確定正則表達式列表?-->??
  • ?????????????<value>com\.mucfc\.msm\.service\.impl\...*ServiceImpl.*</value?>??
  • ??????????</list>??
  • ??????</property>??
  • </bean?>??

  • 5、執(zhí)行結(jié)果:

    ?

    寫了一個簡單的單元測試如下:

    ?

    [java]?view plain?copy
  • @Test??
  • public?void?getSettUnitBySettUnitIdTest()?{??
  • ????String?systemId?=?"CES";??
  • ????String?merchantId?=?"133";??
  • ????SettUnit?configSettUnit?=?settUnitService.getSettUnitBySettUnitId(systemId,?merchantId,?"ESP");??
  • ????SettUnit?configSettUnit1?=?settUnitService.getSettUnitBySettUnitId(systemId,?merchantId,?"ESP");??
  • ????boolean?flag=?(configSettUnit?==?configSettUnit1);??
  • ????System.out.println(configSettUnit);??
  • ????logger.info("查找結(jié)果"?+?configSettUnit.getBusinessType());??
  • ????
  • ??//??localSecondFIFOCache.put("configSettUnit",?configSettUnit.getBusinessType());??
  • ?//??String?string?=?localSecondFIFOCache.get("configSettUnit");??
  • ??????logger.info("查找結(jié)果"?+?string);??
  • }??
  • 這是第一次執(zhí)行單元測試的過程:

    ?

    MethodCacheInterceptor這個類中打了斷點,然后每次查詢前都會先進入這個方法

    ?


    ?

    依次運行,發(fā)現(xiàn)沒有緩存,所以會直接去查數(shù)據(jù)庫

    打印了出來的SQL語句:

    第二次執(zhí)行:

    因為第一次執(zhí)行時,已經(jīng)寫入緩存了。所以第二次直接從緩存中取數(shù)據(jù)

    3、取兩次的結(jié)果進行地址的對比:

    發(fā)現(xiàn)兩個不是同一個對象,沒錯,是對的。如果是使用ehcache的話,那么二者的內(nèi)存地址會是一樣的。那是因為redis和ehcache使用的緩存機制是不一樣的。ehcache是基于本地電腦的內(nèi)存使用緩存,所以使用緩存取數(shù)據(jù)時直接在本地電腦上取。轉(zhuǎn)換成java對象就會是同一個內(nèi)存地址,而redis它是在裝有redis服務(wù)的電腦上(一般是另一臺電腦),所以取數(shù)據(jù)時經(jīng)過傳輸?shù)奖镜?#xff0c;會對應(yīng)到不同的內(nèi)存地址,所以用==來比較會返回false。但是它確實是從緩存中去取的,這點我們從上面的斷點可以看到。

    http://blog.csdn.net/evankaka/article/details/50396325

    總結(jié)

    以上是生活随笔為你收集整理的Redis整合Spring结合使用缓存实例(转)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。