繼上一篇Solr和Spring Data Solr學習,咱們思考一個問題,使用Solr的目的是什麼?確定是爲了加快服務器的相應速度。由於即便不適用Solr,經過請求數據庫咱們同樣能完成搜索功能,可是這樣會給服務器形成很大的壓力。html
而Solr僅僅是在搜索功能中用到了,可是大量請求的數據不只僅出如今搜索中,好比用戶的登陸信息,雖然數據量很小,可是整個項目每刷新一次頁面都要請求一次用戶登陸的Token信息,也會拖慢服務器的響應速度。咱們一般有兩中解決方式:1.數據緩存;2.網頁靜態化。java
其實咱們在Shiro實現用戶-角色-權限管理系統中已經用到了緩存技術,今天咱們瞭解一下Redis緩存技術。git
項目開源地址: Githubgithub
Redis是一款開源的Key-Value數據庫。首先咱們要去 官網 下載Redis,因爲筆者使用的是MacOS系統,和Windows系統有所不一樣。redis
安裝過程再也不敘述,這裏提供兩個教程:spring
<br/>緩存
redis-server redis-server &
建議使用第二個命令,用第二個命令啓動了redis server後能繼續輸入命令,使用第一個命令則不行。服務器
若是終端中顯示以下logo表示redis啓動成功:
<br/>
上面僅僅是啓動了Redis Server,但Redis是一種Key-Value型數據庫,也包含了一些查詢數據庫的命令,操做redis命令的入口就是: redis/bin/redis-cli
./bin/redis-cli redis-cli
keys *
flushall
更多的Redis命令能夠參看:redis中文文檔
<br/>
以前學習Solr的時候用到了Spring Data Solr,如今學習Redis,Spring提供了Spring Data Redis用來實現經過配置文件的方式訪問redis服務。Spring Data Redis對Redis底層開發包(Jedis, JRedis, and RJC)進行了高度封裝,RedisTemplate
提供了redis各類操做、異常處理及序列化。
Jedis
Jedis是Redis官方推出的一款面向Java的客戶端,提供了不少藉口供Java語言調用。
Spring Data Redis針對Jedis提供了以下功能:
RedisTemplate
類。<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.8.1</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.7.2.RELEASE</version> </dependency>
redis.host=127.0.0.1 redis.port=6379 redis.pass= redis.database=0 redis.maxIdle=300 redis.maxWait=3000 redis.testOnBorrow=true
解釋
redis.host
是安裝redis server的客戶端IP地址,若是安裝在本機上就是127.0.0.1,若是安裝在服務器上請修改成服務器的IP地址。redis.port
是redis server的默認端口,你安裝了redis,就默認使用這個端口號。redis.pass
是訪問redis server的密碼,通常咱們不設置。redis.database=0
表明使用的是redis默認提供的db0這個數據庫。redis-maxIdle
是redis server的最大空閒數。redis-maxWait
是鏈接redis時的最大等待毫秒數。redis-testOnBorrow
在提取一個redis實例時,是否提早進行驗證操做;若是爲true,則獲得的jedis實例均是可用的。<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="classpath:other/*.properties"/> <!-- redis 相關配置 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!-- 最大空閒數 --> <property name="maxIdle" value="${redis.maxIdle}"/> <!-- 鏈接時最大的等待時間(毫秒) --> <property name="maxWaitMillis" value="${redis.maxWait}"/> <!-- 在提取一個jedis實例時,是否提早進行驗證操做;若是爲true,則獲得的jedis實例均是可用的 --> <property name="testOnBorrow" value="${redis.testOnBorrow}"/> </bean> <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="poolConfig" ref="poolConfig"/> </bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory"/> </bean> </bean>
本實例源碼:Github
首先加載配置文件spring-redis.xml
,注入RedisTemplate
模板類:
@Autowired private RedisTemplate redisTemplate;
RedisTemplate
提供的不少操做redis數據庫的方法都是boundxxOps
這種。
@Test public void setValue(){ redisTemplate.boundValueOps("name").set("tycoding"); }
若是配置都正常的狀況下,運行此方法就能向db0數據庫中添加一條key爲name
的記錄;那麼咱們在redis命令行中查看全部的key:
奇怪,我添加的key明明是name
,爲何查出來的確實一堆亂碼值呢?咱們再使用redis命令行單獨添加一條記錄:
set testK testV
此時咱們又發現,使用redis原生命令添加的數據是不會亂碼的;那麼就確定是Spring Data Redis的緣由了。經查詢是由於redisTemplate模板類在操做redis序列化的緣由,咱們要手動配置序列化方式爲:StringRedisSerializer
修改以前建立的spring-redis.xml
配置文件:
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory"/> <!-- 序列化策略 推薦使用StringRedisSerializer --> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name="hashKeySerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/> </property> <property name="hashValueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/> </property> </bean>
再次添加數據
@Test public void getValue(){ Object name = redisTemplate.boundValueOps("name").get(); System.out.println(name); }
@Test public void deleteValue(){ redisTemplate.delete("name"); }
@Test public void setValueBySet(){ redisTemplate.boundSetOps("nameset").add("tycoding"); }
@Test public void getValueBySet(){ Set nameset = redisTemplate.boundSetOps("nameset").members(); System.out.println(nameset); }
@Test public void deleteValueBySet(){ redisTemplate.boundSetOps("nameset").remove("塗陌"); }
@Test public void deleteAllValueByset(){ redisTemplate.delete("nameset"); }
右壓棧,後添加的對象排在後邊
@Test public void setRightValueByList(){ redisTemplate.boundListOps("namelist").rightPush("tycoding"); redisTemplate.boundListOps("namelist").rightPush("塗陌"); }
顯示右壓棧集合
@Test public void getRightValueByListI(){ List namelist = redisTemplate.boundListOps("namelist").range(0, 10); System.out.println(namelist); }
左壓棧,後添加的對象排在前面
@Test public void setLeftValueByList(){ redisTemplate.boundListOps("namelist2").leftPush("tycoding"); redisTemplate.boundListOps("namelist2").leftPush("塗陌"); }
顯示左壓棧的集合:
@Test public void getLeftValueByList(){ List name2 = redisTemplate.boundListOps("namelist2").range(0, 10); System.out.println(name2); }
根據索引查詢集合中的元素
@Test public void searchByIndex(){ Object namelist = redisTemplate.boundListOps("namelist").index(1); System.out.println(namelist); }
@Test public void setValueByHash(){ redisTemplate.boundHashOps("namehash").put("a","tycoding"); }
@Test public void getKeysByHash(){ Set namehash = redisTemplate.boundHashOps("namehash").keys(); System.out.println(namehash); }
@Test public void getValuesByHash(){ List namehash = redisTemplate.boundHashOps("namehash").values(); System.out.println(namehash); }
@Test public void getValueByHash(){ Object o = redisTemplate.boundHashOps("namehash").get("a"); System.out.println(o); }
@Test public void deleteValueByHash(){ redisTemplate.boundHashOps("namehash").delete("a"); }
<br/>
上面說了一大堆,沒有實際的測試,着實不清楚Redis究竟效果如何,是否是真的提升了訪問速度?
下面咱們以查詢數據庫全部值的功能來看一下使用Redis緩存和未使用緩存直接查詢數據庫所用時間。
本例源碼地址:Github
未使用Redis緩存,直接請求數據庫
public List<Goods> findAll() { return goodsMapper.findAll(); }
使用了Redis緩存
首先經過boundHashOps
獲取Redis數據庫中是否存在KEY爲all
的數據,有的話就返回;沒有的話就查詢數據庫並將查詢到的數據添加到Redis數據庫中,且KEY爲all
public List<Goods> findAll() { List<Goods> contentList = (List<Goods>) redisTemplate.boundHashOps("goods").get("all"); if (contentList == null) { //說明緩存中沒有數據 System.out.println("從數據庫中讀取數據放入redis..."); contentList = goodsMapper.findAll(); redisTemplate.boundHashOps("goods").put("all", contentList); //存入redis中 } else { System.out.println("從緩存中讀取數據..."); } // return goodsMapper.findAll(); return contentList; }
@Test public void run1() { Long startTime = System.currentTimeMillis(); //開始時間 goodsMapper.findAll(); Long endTime = System.currentTimeMillis(); //結束時間 System.out.println("查詢數據庫--共耗時:" + (endTime - startTime) + "毫秒"); //1007毫秒 } @Test public void run2() { Long startTime = System.currentTimeMillis(); //開始時間 goodsService.findAll(); Long endTime = System.currentTimeMillis(); //結束時間 System.out.println("從redis中讀取全部數據,共耗時:" + (endTime - startTime) + "毫秒"); }
在測試類中調用Service層的這兩個方法,獲得的結果以下:
查詢數據庫--共耗時:1047毫秒 從redis中讀取全部數據,共耗時:197毫秒
<br/>
若是你們有興趣,歡迎你們加入個人Java交流技術羣:671017003 ,一塊兒交流學習Java技術。博主目前一直在自學JAVA中,技術有限,若是能夠,會盡力給你們提供一些幫助,或是一些學習方法,固然羣裏的大佬都會積極給新手答疑的。因此,別猶豫,快來加入咱們吧!
<br/>
If you have some questions after you see this article, you can contact me or you can find some info by clicking these links.