继上一篇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.