一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|數據庫技術|

服務器之家 - 數據庫 - Redis - Redis整合Spring結合使用緩存實例

Redis整合Spring結合使用緩存實例

2019-10-27 16:50林炳文Evankaka Redis

這篇文章主要介紹了Redis整合Spring結合使用緩存實例,介紹了如何在Spring中配置redis,并通過Spring中AOP的思想,將緩存的方法切入到有需要進入緩存的類或方法前面。需要的朋友可以參考下

一、Redis介紹
什么是Redis?
      redis是一個key-value存儲系統。和Memcached類似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。這些數據類型都支持push/pop、add/remove及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支持各種不同方式的排序。與memcached一樣,為了保證效率,數據都是緩存在內存中。區別的是redis會周期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件,并且在此基礎上實現了master-slave(主從)同步。
它有什么特點?
(1)Redis數據庫完全在內存中,使用磁盤僅用于持久性。
(2)相比許多鍵值數據存儲,Redis擁有一套較為豐富的數據類型。
(3)Redis可以將數據復制到任意數量的從服務器。
Redis 優勢?
 (1)異??焖伲篟edis的速度非???,每秒能執行約11萬集合,每秒約81000+條記錄。
 (2)支持豐富的數據類型:Redis支持最大多數開發人員已經知道像列表,集合,有序集合,散列數據類型。這使得它非常容易解決各種各樣的問題,因為我們知道哪些問題是可以處理通過它的數據類型更好。
(3)操作都是原子性:所有Redis操作是原子的,這保證了如果兩個客戶端同時訪問的Redis服務器將獲得更新后的值。
(4)多功能實用工具:Redis是一個多實用的工具,可以在多個用例如緩存,消息,隊列使用(Redis原生支持發布/訂閱),任何短暫的數據,應用程序,如Web應用程序會話,網頁命中計數等。
Redis 缺點?
(1)單線程
(2)耗內存
二、使用實例
本文使用maven+eclipse+sping
1、引入jar包

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
  <!--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加入如下配置

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!-- 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服務器中心 -->
  <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一些配置數據redis.properties如下:

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#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=
 
#設置緩存失效時間
com.service.impl.xxxRecordManager= 60
com.service.impl.xxxSetRecordManager= 60
defaultCacheExpireTime=3600
 
fep.local.cache.capacity =10000

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

 
?
1
 
2
3
4
5
6
7
8
9
<!-- 引入properties配置文件 -->
 <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="locations">
    <list>
      <value>classpath:properties/*.properties</value>
      <!--要是有多個配置文件,只需在這里繼續添加即可 -->
    </list>
  </property>
</bean>

3、一些工具類
(1)RedisUtil
上面的bean中,RedisUtil是用來緩存和去除數據的實例

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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;
 
  /**
   * 批量刪除對應的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);
  }
 
  /**
   * 刪除對應的value
   *
   * @param key
   */
  public void remove(final String key) {
    if (exists(key)) {
      redisTemplate.delete(key);
    }
  }
 
  /**
   * 判斷緩存中是否有對應的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,這是用來給不同的方法來加入判斷如果緩存存在數據,從緩存取數據。否則第一次從數據庫取,并將結果保存到緩存 中去。

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
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-workspacemsmmsm_coresrcmainjavacommucfcmsmcommoncacheConf.properties"); 
       //配置文件位置直接被寫死,有需要自己修改下
       InputStream in = new FileInputStream(f); 
//     InputStream in = getClass().getClassLoader().getResourceAsStream(
//         "D:lunaJee-workspacemsmmsm_coresrcmainjavacommucfcmsmcommoncacheConf.properties");
      Properties p = new Properties();
      p.load(in);
      // 分割字符串
      String[] targetNames = p.getProperty("targetNames").split(",");
      String[] methodNames = p.getProperty("methodNames").split(",");
 
      // 加載過期時間設置
      defaultCacheExpireTime = Long.valueOf(p.getProperty("defaultCacheExpireTime"));
      xxxRecordManagerTime = Long.valueOf(p.getProperty("com.service.impl.xxxRecordManager"));
      xxxSetRecordManagerTime = Long.valueOf(p.getProperty("com.service.impl.xxxSetRecordManager"));
      // 創建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();
    // 不需要緩存的內容
    //if (!isAddCache(StringUtil.subStrForLastDot(targetName), methodName)) {
    if (!isAddCache(targetName, methodName)) {
      // 執行方法返回結果
      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;
  }
 
  /**
   * 創建緩存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加入如下配置,有多個類或方法可以配置多個

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
<!-- 需要加入緩存的類或方法 -->
<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、執行結果:
寫了一個簡單的單元測試如下:

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
13
14
@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("查找結果" + configSettUnit.getBusinessType());
  
 // localSecondFIFOCache.put("configSettUnit", configSettUnit.getBusinessType());
 // String string = localSecondFIFOCache.get("configSettUnit");
   logger.info("查找結果" + string);
}

這是第一次執行單元測試的過程:
MethodCacheInterceptor這個類中打了斷點,然后每次查詢前都會先進入這個方法

Redis整合Spring結合使用緩存實例

依次運行,發現沒有緩存,所以會直接去查數據庫

Redis整合Spring結合使用緩存實例

打印了出來的SQL語句:

Redis整合Spring結合使用緩存實例

第二次執行:
因為第一次執行時,已經寫入緩存了。所以第二次直接從緩存中取數據

Redis整合Spring結合使用緩存實例

3、取兩次的結果進行地址的對比:
發現兩個不是同一個對象,沒錯,是對的。如果是使用ehcache的話,那么二者的內存地址會是一樣的。那是因為redis和ehcache使用的緩存機制是不一樣的。ehcache是基于本地電腦的內存使用緩存,所以使用緩存取數據時直接在本地電腦上取。轉換成java對象就會是同一個內存地址,而redis它是在裝有redis服務的電腦上(一般是另一臺電腦),所以取數據時經過傳輸到本地,會對應到不同的內存地址,所以用==來比較會返回false。但是它確實是從緩存中去取的,這點我們從上面的斷點可以看到。

Redis整合Spring結合使用緩存實例

以上就是本文的全部內容,希望對大家的學習有所幫助。

延伸 · 閱讀

精彩推薦
  • RedisRedis全量復制與部分復制示例詳解

    Redis全量復制與部分復制示例詳解

    這篇文章主要給大家介紹了關于Redis全量復制與部分復制的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Redis爬蟲具有一定的參考學習...

    豆子先生5052019-11-27
  • Redisredis 交集、并集、差集的具體使用

    redis 交集、并集、差集的具體使用

    這篇文章主要介紹了redis 交集、并集、差集的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友...

    xiaojin21cen10152021-07-27
  • Redisredis中如何使用lua腳本讓你的靈活性提高5個逼格詳解

    redis中如何使用lua腳本讓你的靈活性提高5個逼格詳解

    這篇文章主要給大家介紹了關于redis中如何使用lua腳本讓你的靈活性提高5個逼格的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具...

    一線碼農5812019-11-18
  • RedisRedis如何實現數據庫讀寫分離詳解

    Redis如何實現數據庫讀寫分離詳解

    Redis的主從架構,能幫助我們實現讀多,寫少的情況,下面這篇文章主要給大家介紹了關于Redis如何實現數據庫讀寫分離的相關資料,文中通過示例代碼介紹...

    羅兵漂流記6092019-11-11
  • RedisRedis 事務知識點相關總結

    Redis 事務知識點相關總結

    這篇文章主要介紹了Redis 事務相關總結,幫助大家更好的理解和學習使用Redis,感興趣的朋友可以了解下...

    AsiaYe8232021-07-28
  • Redisredis實現排行榜功能

    redis實現排行榜功能

    排行榜在很多地方都能使用到,redis的zset可以很方便地用來實現排行榜功能,本文就來簡單的介紹一下如何使用,具有一定的參考價值,感興趣的小伙伴們...

    乘月歸5022021-08-05
  • RedisRedis的配置、啟動、操作和關閉方法

    Redis的配置、啟動、操作和關閉方法

    今天小編就為大家分享一篇Redis的配置、啟動、操作和關閉方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧 ...

    大道化簡5312019-11-14
  • Redis詳解Redis復制原理

    詳解Redis復制原理

    與大多數db一樣,Redis也提供了復制機制,以滿足故障恢復和負載均衡等需求。復制也是Redis高可用的基礎,哨兵和集群都是建立在復制基礎上實現高可用的...

    李留廣10222021-08-09
主站蜘蛛池模板: 精品一卡2卡3卡4卡5卡亚洲 | 欧美日韩va | 草莓香蕉榴莲丝瓜秋葵绿巨人在线看 | 日韩在线观看免费 | 单亲乱l仑在线观看免费观看 | 久久视频在线视频观看天天看视频 | 无限好资源免费观看 | 国产欧美日韩亚洲精品区2345 | 国产久草在线 | 短篇最污的乱淫伦小说全集 | 4455四色永久免费 | 国产精品免费视频能看 | 国产在线视频福利 | 国产欧美在线播放 | 国产精品久久香蕉免费播放 | 高跟翘臀老师后进式视频 | 91久操 | 无人区国产大片 | 99久久国产综合精品女不卡 | 国产自产在线 | 大奶喷水| 亚洲国产视频一区 | 国产精品夜色视频一级区 | 欧美黑人性 | 日本深夜影院 | 小草视频免费观看在线 | 无码骚夜夜精品 | 国产精品免费综合一区视频 | 秋霞鲁丝影院久久人人综合 | 美女和男人免费网站视频 | 亚洲日本va午夜中文字幕 | 国产精品天天影视久久综合网 | 青草网在线观看 | 亚洲丰满女人ass硕大 | 国产精品国产三级在线专区 | 吉川爱美与黑人解禁 | 日韩欧美一区二区三区 | 国产精品视频一区二区三区不卡 | 欧美日韩在线观看精品 | 久久精品视在线观看2 | 91久久偷偷做嫩草影院免费看 |