SSM框架上集合Redis技術
為了完成畢業設計,將之前做的電商網站進行整改,目前需要整合上Redis,說明一下步驟,為到時候答辯做個筆記
前言:Redis簡介(簡單概述)
- key-value儲存系統
- 支援string,list連結串列,set集合,hash表
- 符合原子性(成功則提交,失敗則回滾),要麼就完成,要麼就不完成,當作什麼都沒做,就是一定要完成一整套的操作,不可中途退出
- 無需考慮多執行緒的併發問題
- 快取在記憶體中
以上是一些簡述,我只用到這些,用到哪些寫哪些,沒用過的就沒有寫,(寫上也不一定會用,額,到時候再補充)
第一步:下載Redis(跟沒說一樣,但是這裡有關於Redis閃退的問題)
安裝好Redis後,開啟Redis服務有時會發現彈出一個視窗就閃退;
- 目前已知的原因只發現一個:已經有Redis程序在啟動
解決方案:工作管理員 -----> 找到Redis程序 -----> 結束關閉它 -----> 再次重啟
- 還有一種情況閃退,有解決方案,但是還沒弄清問題產生的原因,所以先放上解決方案:
更改redis資料夾中的 redis.windows.conf
#bind 127.0.0.1 去掉#
然後重啟Redis,或者CMD上 cd 到 Redis儲存路徑 執行 redis-server.exe redis.windows.conf
有的時候還是會報錯,講道理,這裡真不知道為什麼!!(百度了好久,看來還是不夠認真)
如果還有錯,那就這樣:
redis-cli.exe -----> shutdown -----> exit -----> edis-server.exe redis.windows.conf
依次執行命令列,難受(希望有人告訴我),額,繼續整合步驟!
第二步:編寫Redis配置檔案(redis.properties、spring-redis.xml)
這裡說明一下redis.properties。後續會有SpringBoot的更換,換成yml的格式,先說一下,以免到時候忘掉
還有,我的配置檔案目錄形式如下:
將spring的配置檔案放入spring資料夾中,方便管理,在spring-dao.xml
<bean class="com.zhaoyu.shop.util.EncryptPropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
<value>classpath:redis.properties</value>
</list>
</property>
<property name="fileEncoding" value="UTF-8" />
</bean>
這裡一個是jdbc的配置,一個是redis的配置;
- redis.properties的編寫:
redis.hostname=127.0.0.1
redis.port=6379
redis.database=0
redis.pool.maxActive=600
redis.pool.maxIdle=300
redis.pool.maxWait=3000
redis.pool.testOnBorrow=true
這裡不做過多的說明了,強調一下預設埠號 6379 (之前被問過,竟然忘了。。)
這個properties的編寫和資料庫連線(jdbc.properties)的一樣
- spring-redis.xml的編寫
-
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> <!-- Redis連線池的設定 --> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!-- 控制一個pool可分配多少個Jedis例項 --> <property name="maxTotal" value="${redis.pool.maxActive}" /> <!-- 連線池中最多可空閒maxIdle個連線,這裡取值為20,表示即使沒有資料庫連線時依然可以保持20個空閒的連線,而不被清除,隨時處於待命狀態 --> <property name="maxIdle" value="${redis.pool.maxIdle}" /> <!-- 最大連線時間,當沒有可用連線時 --> <property name="maxWaitMillis" value="${redis.pool.maxWait}" /> <!-- 在獲取連線時檢查有效性 --> <property name="testOnBorrow" value="${redis.pool.testOnBorrow}" /> </bean> <!-- 建立Redis連線池,並作相關配置 --> <bean id="jedisWritePool" class="com.zhaoyu.shop.cache.JedisPoolWriper" depends-on="jedisPoolConfig"> <constructor-arg index="0" ref="jedisPoolConfig" /> <constructor-arg index="1" value="${redis.hostname}" /> <constructor-arg index="2" value="${redis.port}" type="int" /> </bean> <bean id="jedisKeys" class="com.zhaoyu.shop.cache.JedisUtil$Keys" scope="singleton"> <constructor-arg ref="jedisUtil"></constructor-arg> </bean> <bean id="jedisStrings" class="com.zhaoyu.shop.cache.JedisUtil$Strings" scope="singleton"> <constructor-arg ref="jedisUtil"></constructor-arg> </bean> <bean id="jedisLists" class="com.zhaoyu.shop.cache.JedisUtil$Lists" scope="singleton"> <constructor-arg ref="jedisUtil"></constructor-arg> </bean> <bean id="jedisSets" class="com.zhaoyu.shop.cache.JedisUtil$Sets" scope="singleton"> <constructor-arg ref="jedisUtil"></constructor-arg> </bean> <bean id="jedisHash" class="com.zhaoyu.shop.cache.JedisUtil$Hash" scope="singleton"> <constructor-arg ref="jedisUtil"></constructor-arg> </bean> <!-- 建立Redis工具類,封裝好Redis的連線並進行相關操作 --> <bean id="jedisUtil" class="com.zhaoyu.shop.cache.JedisUtil" scope="singleton"> <property name="jedisPool"> <ref bean="jedisWritePool" /> </property> </bean> </beans>
說明一下上述的配置檔案:
- 首先設定Redis連線池
<!-- Redis連線池的設定 -->
<bean id="jedisPoolConfig"
class="redis.clients.jedis.JedisPoolConfig">
<!-- 控制一個pool可分配多少個Jedis例項 -->
<property name="maxTotal" value="${redis.pool.maxActive}" />
<!-- 連線池中最多可空閒maxIdle個連線,這裡取值為20,表示即使沒有資料庫連線時依然可以保持20個空閒的連線,而不被清除,隨時處於待命狀態 -->
<property name="maxIdle" value="${redis.pool.maxIdle}" />
<!-- 最大連線時間,當沒有可用連線時 -->
<property name="maxWaitMillis" value="${redis.pool.maxWait}" />
<!-- 在獲取連線時檢查有效性 -->
<property name="testOnBorrow"
value="${redis.pool.testOnBorrow}" />
</bean>
<property name="maxTotal" value="${redis.pool.maxActive}" />
這裡有個value,和jdbc的連線池一樣,動態獲取redis.properties中的對應值
- 建立Redis連線池,配置其屬性
<!-- 建立Redis連線池,並作相關配置 -->
<bean id="jedisWritePool"
class="com.zhaoyu.shop.cache.JedisPoolWriper"
depends-on="jedisPoolConfig">
<constructor-arg index="0" ref="jedisPoolConfig" />
<constructor-arg index="1" value="${redis.hostname}" />
<constructor-arg index="2" value="${redis.port}"
type="int" />
</bean>
<constructor-arg index="2" value="${redis.port}" type="int" />
這裡的value和上面一樣
- 建立Redis工具類,封裝好Redis的連線並進行相關操作
<!-- 建立Redis工具類,封裝好Redis的連線並進行相關操作 -->
<bean id="jedisUtil" class="com.zhaoyu.shop.cache.JedisUtil"
scope="singleton">
<property name="jedisPool">
<ref bean="jedisWritePool" />
</property>
</bean>
<bean id="jedisKeys" class="com.zhaoyu.shop.cache.JedisUtil$Keys"
scope="singleton">
<constructor-arg ref="jedisUtil"></constructor-arg>
</bean>
<bean id="jedisStrings"
class="com.zhaoyu.shop.cache.JedisUtil$Strings" scope="singleton">
<constructor-arg ref="jedisUtil"></constructor-arg>
</bean>
<bean id="jedisLists"
class="com.zhaoyu.shop.cache.JedisUtil$Lists" scope="singleton">
<constructor-arg ref="jedisUtil"></constructor-arg>
</bean>
<bean id="jedisSets" class="com.zhaoyu.shop.cache.JedisUtil$Sets"
scope="singleton">
<constructor-arg ref="jedisUtil"></constructor-arg>
</bean>
<bean id="jedisHash" class="com.zhaoyu.shop.cache.JedisUtil$Hash"
scope="singleton">
<constructor-arg ref="jedisUtil"></constructor-arg>
</bean>
這塊的配置就是對於Redis的相關操作,分別為key,String,List,set,hash
現在配置檔案就完成了;
第三步:編寫redis連線池類(jedisWritePool)管理連線
這裡說到了jedis,我的理解就是jedis就是集成了redis的一些命令操作,封裝了redis的java客戶端。提供了連線池管理;
話句話說,jedis就是redis的客戶端;
jedisWritePool.java程式碼如下:
/**
* 強指定redis的JedisPool介面建構函式,這樣才能在centos成功建立jedispool
*
* @author xiangze
*
*/
public class JedisPoolWriper {
/**
* redis連線池物件
*/
private JedisPool jedisPool;
public JedisPoolWriper(final JedisPoolConfig poolConfig, final String host,
final int port) {
try {
jedisPool = new JedisPool(poolConfig, host, port);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 獲取 redis連線池物件
* @return
*/
public JedisPool getJedisPool() {
return jedisPool;
}
/**
* 注入redis連線池物件
* @param jedisPool
*/
public void setJedisPool(JedisPool jedisPool) {
this.jedisPool = jedisPool;
}
}
這裡就是實現構造方法,傳參連線池配置資訊,host地址,port埠號,然後通過get和set方法,實現對連線池的獲取和注入
第四步:編寫redis操作類(JedisUtil)操作Redis資料庫
JedisUtil.java:程式碼如下
public class JedisUtil {
/** 操作Key的方法 */
public Keys KEYS;
/** 對儲存結構為String型別的操作 */
public Strings STRINGS;
/** 對儲存結構為List型別的操作 */
public Lists LISTS;
/** 對儲存結構為Set型別的操作 */
public Sets SETS;
/** 對儲存結構為HashMap型別的操作 */
public Hash HASH;
private JedisPool jedisPool;
/**
* 從Jedis連線池中獲取redis連線池
* @return
*/
public JedisPool getJedisPool() {
return jedisPool;
}
/**
* 設定redis連線池
* @param jedisPoolWriper
*/
public void setJedisPool(JedisPoolWriper jedisPoolWriper) {
this.jedisPool = jedisPoolWriper.getJedisPool();
}
/**
* 從jedis連線池中獲取獲取jedis物件
*
* @return
*/
public Jedis getJedis() {
return jedisPool.getResource();
}
}
這就是一個簡易的Jedis連線池工具類,比如像快取生存時間等一些其他功能沒有設定。。。
第五步:Redis快取技術實現
這裡就簡述一個我的商品類別一覽資訊獲取的redis快取技術
public class ShopCategoryServiceImpl implements ShopCategoryService {
@Autowired
private JedisUtil.Strings jedisStrings;
@Autowired
private JedisUtil.Keys jedisKeys;
@Autowired
private ShopCategoryDao shopCategoryDao;
private static String SCLISTKEY = "shopcategorylist";
@Override
public List<ShopCategory> getFirstLevelShopCategoryList()
throws IOException {
//定義redis的key字首
String key = SCLISTKEY;
//定義接受物件
List<ShopCategory> shopCategoryList = null;
//定義jackson資料轉換操作類
ObjectMapper mapper = new ObjectMapper();
if (!jedisKeys.exists(key)) {
ShopCategory shopCategoryCondition = new ShopCategory();
// 當shopCategoryId不為空的時候,查詢的條件會變為 where parent_id is null
shopCategoryCondition.setShopCategoryId(-1L);
shopCategoryList = shopCategoryDao
.queryShopCategory(shopCategoryCondition);
String jsonString = mapper.writeValueAsString(shopCategoryList);
jedisStrings.set(key, jsonString);
} else {
String jsonString = jedisStrings.get(key);
JavaType javaType = mapper.getTypeFactory()
.constructParametricType(ArrayList.class,
ShopCategory.class);
shopCategoryList = mapper.readValue(jsonString, javaType);
}
return shopCategoryList;
}
}
- 首先,注入JedisUtil工具類中的String,key欄位屬性
- 定義一個key 為 SCLISTKEY,值是shopcategorylist
- 判斷redis中是否有需要的資料,若為true,則查詢出資料,通過ObjectMapper類將ArrayList物件轉換成ShopCategory(商品類別)類的物件
- 若redis中沒有相關資料,則從資料庫中查詢,並將其準換成(查出的資料是list)string,然後set到redis中對應的key值