javascript
Redis及Spring-Data-Redis入门学习
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
繼上一篇Solr和Spring Data Solr學(xué)習(xí),我們思考一個(gè)問題,使用Solr的目的是什么?肯定是為了加快服務(wù)器的相應(yīng)速度。因?yàn)榧词共贿m用Solr,通過請(qǐng)求數(shù)據(jù)庫(kù)我們一樣能完成搜索功能,但是這樣會(huì)給服務(wù)器造成很大的壓力。
而Solr僅僅是在搜索功能中用到了,但是大量請(qǐng)求的數(shù)據(jù)不僅僅出現(xiàn)在搜索中,比如用戶的登錄信息,雖然數(shù)據(jù)量很小,但是整個(gè)項(xiàng)目每刷新一次頁(yè)面都要請(qǐng)求一次用戶登錄的Token信息,也會(huì)拖慢服務(wù)器的響應(yīng)速度。我們通常有兩中解決方式:1.數(shù)據(jù)緩存;2.網(wǎng)頁(yè)靜態(tài)化。
其實(shí)我們?cè)赟hiro實(shí)現(xiàn)用戶-角色-權(quán)限管理系統(tǒng)中已經(jīng)用到了緩存技術(shù),今天我們了解一下Redis緩存技術(shù)。
項(xiàng)目開源地址: Github
安裝Redis
Redis是一款開源的Key-Value數(shù)據(jù)庫(kù)。首先我們要去 官網(wǎng) 下載Redis,由于筆者使用的是MacOS系統(tǒng),和Windows系統(tǒng)有所不同。
安裝過程不再敘述,這里提供兩個(gè)教程:
-
Windows: Redis安裝教程
-
MacOS&Linux: Redis安裝教程
<br/>
啟動(dòng)Redis
redis-server redis-server &建議使用第二個(gè)命令,用第二個(gè)命令啟動(dòng)了redis server后能繼續(xù)輸入命令,使用第一個(gè)命令則不行。
如果終端中顯示如下logo表示redis啟動(dòng)成功:
<br/>
操縱Redis
上面僅僅是啟動(dòng)了Redis Server,但Redis是一種Key-Value型數(shù)據(jù)庫(kù),也包含了一些查詢數(shù)據(jù)庫(kù)的命令,操作redis命令的入口就是: redis/bin/redis-cli
./bin/redis-cliredis-cli更多的Redis命令可以參看:redis中文文檔
<br/>
Spring Data Redis
之前學(xué)習(xí)Solr的時(shí)候用到了Spring Data Solr,現(xiàn)在學(xué)習(xí)Redis,Spring提供了Spring Data Redis用來實(shí)現(xiàn)通過配置文件的方式訪問redis服務(wù)。Spring Data Redis對(duì)Redis底層開發(fā)包(Jedis, JRedis, and RJC)進(jìn)行了高度封裝,RedisTemplate提供了redis各種操作、異常處理及序列化。
Jedis
Jedis是Redis官方推出的一款面向Java的客戶端,提供了很多借口供Java語(yǔ)言調(diào)用。
Spring Data Redis針對(duì)Jedis提供了如下功能:
- 1.連接池自動(dòng)管理,提供了一個(gè)高度封住的RedisTemplate類。
- 2.針對(duì)jedis客戶端中大量api進(jìn)行歸類封裝,將同一類型操作封裝為operation接口: ValueOperations: 簡(jiǎn)單的K-V操作 SetOperations: set類型數(shù)據(jù)操作 ZSetOperations: zset類型數(shù)據(jù)操作 HashOperations: 針對(duì)Map類型的數(shù)據(jù)操作 ListOperations: 針對(duì)List類型的數(shù)據(jù)操作
準(zhǔn)備
導(dǎo)入依賴
<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>創(chuàng)建redis-config.properties
redis.host=127.0.0.1 redis.port=6379 redis.pass= redis.database=0 redis.maxIdle=300 redis.maxWait=3000 redis.testOnBorrow=true解釋
創(chuàng)建spring-redis.xml
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><context:property-placeholder location="classpath:other/*.properties"/><!-- redis 相關(guān)配置 --><bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"><!-- 最大空閑數(shù) --><property name="maxIdle" value="${redis.maxIdle}"/><!-- 連接時(shí)最大的等待時(shí)間(毫秒) --><property name="maxWaitMillis" value="${redis.maxWait}"/><!-- 在提取一個(gè)jedis實(shí)例時(shí),是否提前進(jìn)行驗(yàn)證操作;如果為true,則得到的jedis實(shí)例均是可用的 --><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>實(shí)例
本實(shí)例源碼:Github
首先加載配置文件spring-redis.xml,注入RedisTemplate模板類:
@Autowired private RedisTemplate redisTemplate;值類型
RedisTemplate提供的很多操作redis數(shù)據(jù)庫(kù)的方法都是boundxxOps這種。
添加
@Test public void setValue(){redisTemplate.boundValueOps("name").set("tycoding"); }如果配置都正常的情況下,運(yùn)行此方法就能向db0數(shù)據(jù)庫(kù)中添加一條key為name的記錄;那么我們?cè)趓edis命令行中查看所有的key:
奇怪,我添加的key明明是name,為什么查出來的確實(shí)一堆亂碼值呢?我們?cè)偈褂胷edis命令行單獨(dú)添加一條記錄:
set testK testV此時(shí)我們又發(fā)現(xiàn),使用redis原生命令添加的數(shù)據(jù)是不會(huì)亂碼的;那么就肯定是Spring Data Redis的原因了。經(jīng)查詢是因?yàn)閞edisTemplate模板類在操作redis序列化的原因,我們要手動(dòng)配置序列化方式為:StringRedisSerializer
修改之前創(chuàng)建的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>再次添加數(shù)據(jù)
查詢
@Test public void getValue(){Object name = redisTemplate.boundValueOps("name").get();System.out.println(name); }刪除
@Test public void deleteValue(){redisTemplate.delete("name"); }Set類型
添加
@Test public void setValueBySet(){redisTemplate.boundSetOps("nameset").add("tycoding"); }查詢
@Test public void getValueBySet(){Set nameset = redisTemplate.boundSetOps("nameset").members();System.out.println(nameset); }刪除Set中某一個(gè)值
@Test public void deleteValueBySet(){redisTemplate.boundSetOps("nameset").remove("涂陌"); }刪除整個(gè)Set
@Test public void deleteAllValueByset(){redisTemplate.delete("nameset"); }List類型
右壓棧
右壓棧,后添加的對(duì)象排在后邊
@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); }左壓棧
左壓棧,后添加的對(duì)象排在前面
@Testpublic void setLeftValueByList(){redisTemplate.boundListOps("namelist2").leftPush("tycoding");redisTemplate.boundListOps("namelist2").leftPush("涂陌");}顯示左壓棧的集合:
@Testpublic void getLeftValueByList(){List name2 = redisTemplate.boundListOps("namelist2").range(0, 10);System.out.println(name2);}根據(jù)索引查詢集合中的元素
@Testpublic void searchByIndex(){Object namelist = redisTemplate.boundListOps("namelist").index(1);System.out.println(namelist);}Hash類型
添加
@Testpublic void setValueByHash(){redisTemplate.boundHashOps("namehash").put("a","tycoding");}提取所有的KEY
@Testpublic void getKeysByHash(){Set namehash = redisTemplate.boundHashOps("namehash").keys();System.out.println(namehash);}提取所有的VALUE
@Testpublic void getValuesByHash(){List namehash = redisTemplate.boundHashOps("namehash").values();System.out.println(namehash);}根據(jù)KEY取值
@Testpublic void getValueByHash(){Object o = redisTemplate.boundHashOps("namehash").get("a");System.out.println(o);}根據(jù)KEY移除值
@Testpublic void deleteValueByHash(){redisTemplate.boundHashOps("namehash").delete("a");}<br/>
測(cè)試
上面說了一大堆,沒有實(shí)際的測(cè)試,著實(shí)不清楚Redis究竟效果如何,是不是真的提高了訪問速度?
下面我們以查詢數(shù)據(jù)庫(kù)所有值的功能來看一下使用Redis緩存和未使用緩存直接查詢數(shù)據(jù)庫(kù)所用時(shí)間。
本例源碼地址:Github
未使用Redis緩存,直接請(qǐng)求數(shù)據(jù)庫(kù)
public List<Goods> findAll() {return goodsMapper.findAll(); }使用了Redis緩存
首先通過boundHashOps獲取Redis數(shù)據(jù)庫(kù)中是否存在KEY為all的數(shù)據(jù),有的話就返回;沒有的話就查詢數(shù)據(jù)庫(kù)并將查詢到的數(shù)據(jù)添加到Redis數(shù)據(jù)庫(kù)中,且KEY為all
public List<Goods> findAll() {List<Goods> contentList = (List<Goods>) redisTemplate.boundHashOps("goods").get("all");if (contentList == null) {//說明緩存中沒有數(shù)據(jù)System.out.println("從數(shù)據(jù)庫(kù)中讀取數(shù)據(jù)放入redis...");contentList = goodsMapper.findAll();redisTemplate.boundHashOps("goods").put("all", contentList); //存入redis中} else {System.out.println("從緩存中讀取數(shù)據(jù)...");}// return goodsMapper.findAll();return contentList; }TestTime.java
@Test public void run1() {Long startTime = System.currentTimeMillis(); //開始時(shí)間goodsMapper.findAll();Long endTime = System.currentTimeMillis(); //結(jié)束時(shí)間System.out.println("查詢數(shù)據(jù)庫(kù)--共耗時(shí):" + (endTime - startTime) + "毫秒"); //1007毫秒 }@Test public void run2() {Long startTime = System.currentTimeMillis(); //開始時(shí)間goodsService.findAll();Long endTime = System.currentTimeMillis(); //結(jié)束時(shí)間System.out.println("從redis中讀取所有數(shù)據(jù),共耗時(shí):" + (endTime - startTime) + "毫秒"); }在測(cè)試類中調(diào)用Service層的這兩個(gè)方法,得到的結(jié)果如下:
查詢數(shù)據(jù)庫(kù)--共耗時(shí):1047毫秒從redis中讀取所有數(shù)據(jù),共耗時(shí):197毫秒<br/>
交流
如果大家有興趣,歡迎大家加入我的Java交流技術(shù)群:671017003 ,一起交流學(xué)習(xí)Java技術(shù)。博主目前一直在自學(xué)JAVA中,技術(shù)有限,如果可以,會(huì)盡力給大家提供一些幫助,或是一些學(xué)習(xí)方法,當(dāng)然群里的大佬都會(huì)積極給新手答疑的。所以,別猶豫,快來加入我們吧!
<br/>
聯(lián)系
If you have some questions after you see this article, you can contact me or you can find some info by clicking these links.
- [Blog@TyCoding's blog](http://www.tycoding.cn)
- [GitHub@TyCoding](https://github.com/TyCoding)
- [ZhiHu@TyCoding](https://www.zhihu.com/people/tomo-83-82/activities)
轉(zhuǎn)載于:https://my.oschina.net/u/3955926/blog/2208586
總結(jié)
以上是生活随笔為你收集整理的Redis及Spring-Data-Redis入门学习的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ubuntu与 Fedora之对比
- 下一篇: Spring Boot知识清单