文章目录
1.问题
现在面临这样一个问题:现在把项目跑起来,网站首页的访问压力会很大,因为每次访问都会去数据库查一遍广告表,这样广告表的访问压力会很大,那每个人都访问,每个人都访问,这不是我们最终的一个解决方案了。我们这时候对数据库访问压力太大,那么我们怎么才能降低对数据库的访问压力呢?这时候我们通常会用到缓存,之前讲过一个缓存类的产品,叫Redis,我们现在可以简单回顾一下这个Redis。
2.解决
这个Redis本身是用什么数据库呢?是用NoSQL,它是一种键值对形式的一种数据库,那么Redis更多的会用在哪呢?就是说我们更多的会把它当成一种缓存系统。虽然说它本身也可以实现一种数据的存储,可以实现数据的一个序列化,磁盘序列化,但是我们更多的是把它当成一个内存数据库,就是我们把一些经常访问的数据,把它放到Redis里,然后这样一来,我们再访问的时候,我们可以先查Redis,如果Redis有,就直接从Redis给我们返回数据,就不用对数据库造成访问压力了,所以说像广告这样的数据,只让它查一次就可以了。我们第一次查,向数据库查,查完放到Redis里面,第二次查的时候缓存中有,它会判断缓存中有,然后接下来就会向缓存中查,这样一来它对数据库的访问就没那么大了。3.windows下的Redis服务端
Redis服务一般在Linux下进行部署,为了测试方便,Redis提供了在windows下的一个服务。那么接下来进行wondiws下的部署。-
redis2.8win32
- redis.windows.conf
- redis-cli.exe
- redis-server.exe
打开这个redis-server.exe文件就开启了服务端。把它一起来就完事了。在本地就有一个Redis服务了,然后无哦们测试起来就比较方便一些。
redis-cli.exe是客户端,双击之后直接就连上了。平时我们不需要开这个客户端,只要开服务端就可以了,就可以测试了。
4.Jedis
Jedis是Redis官方推出的操作Redis的一组API。
5.Spring Data Redis
Spring Data Redis是Spring家族的一个子框架,就跟Spring Security差不多,Spring Data Redis就是用来操作Redis的一个框架,那Spring Data Redis和Jedis什么关系呢?他们是封装与被封装的关系。我们都知道Spring的一个原则就是不吃农夫造轮子的,就是别人已经有的东西它不会重新去实现一套。他所作的事情就是去对别人的东西进行封装的。比如说Spring Data Redis技师对Jedis的一个封装,它底层的部分仍然是调用Jedis。那么它封装完又起到什么作用呢?就是起到一个简化开发的作用。就是它给我们封装完后我们的操作会更加简单。但是Spring Data Redis底层不完全是Jedis,因为Spring Data Redis不仅仅是是对Redis的封装,它还可以实现对其他开发包的封装,因为我们操作Redis我们不一定非要用Jedis这种开发包。Jedis是官方推出的开发包,民间还有JRedis,RJC。它还实现了一些连接池的管理。Spring Data Redis针对Jedis提供了如下功能:
-
连接池自动管理,提供了一个高度封装的RedisTemplate类。我们操作Redis就是通过这个类进行操作的。
-
针对Redis客户端中大量的API进行了归类封装,将同一类型操作封装为operation接口
- ValueOperations:简单K-V操作
- SetOperations:Set类型数据操作
- ZSetOperations:zset类型数据操作
- HashOperations:针对Map类型的数据操作
- ListOperations:针对List类型的数据操作
Jedis是一组API,它属于偏底层的东西,它不属于框架,而Spring Data Redis是对Jedis的一种封装,他属于偏上层的东西,他属于框架。
6.Spring Data Redis入门小Demo
首先我们做的第一步就是将这个工程搭建起来。
6.1 准备工作
- 0.构建Maven工程SpringDataRedisDemo
- 1.引入Spring相关依赖,引入Junit依赖
- 2.引入jedis和SpringDataRedis相关依赖
- 3.在resources目录下创建properties文件夹,建立redis-config.properties
- 4.在resources目录下创建spring文件夹,建立applicationContext-redis.xml
1.Spring相关依赖和Junit依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
2.Jedit和SpringDataRedis依赖
<!-- 缓存 -->
<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>
3.redis-config.properties配置
# Redis settings
# server IP 因为redis部署在了本机,所以填写本机的IP地址,如果部署在其他主机上,则填写其他主机的IP地址
redis.host=127.0.0.1
# server port 端口默认是4379
redis.port=6379
# server pass 如果redis有密码,就把密码配上,一般redis是不设置密码的
redis.pass=
# use dbIndex
redis.database=0
# 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例
redis.maxIdle=300
# 表示当borrow(引入)一个jedis实例时,最大的等待时间,如果超过等待时间(毫秒),则直接抛出JedisConnectionException;
redis.maxWait=3000
# 在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的
redis.testOnBorrow=true
4.applicationContext.xml配置
<context:property-placeholder location="classpath*:properties/*.properties" />
<!-- redis 相关配置 -->
<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>
<bean id="JedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}"
p:pool-config-ref="poolConfig" />
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="JedisConnectionFactory" />
</bean>
参数说明:
- maxIdle:最大空闲
- maxWaitMills:连接时最大的等待的毫秒数
- testOnBorrow:在提取一个jedis实例时,是否提前进行验证操作。如果为true,则得到的jedis实例均是可用的。
- JedisConnectionFactory:Jedis的连接工厂类,是Spring Data Redis提供的
6.2 测试
在src/test/java下建立test包,在包中创建TestValue.java文件,因为要弄最简单的key-value形式的这种存储。
TestValue
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:spring/applicationContext-redis.xml")
public class TestValue {
@Autowired
private RedisTemplate redisTemplate;
// 存值
@Test
public void setValue() {
// redisTemplate.boundValueOps方法返回一个操作对象BoundValueOperations,可以直接继续.set()。
redisTemplate.boundValueOps("name").set("ronybo");
}
// 取值
@Test
public void getValue() {
String str = (String)redisTemplate.boundValueOps("name").get();
System.out.println(str);
}
// 删除值
@Test
public void delValue() {
redisTemplate.delete("name");
}
}
TestSet:无序
public class TestSet {
@Autowired
private RedisTemplate redisTemplate;
// 存值
@Test
public void setValue() {
redisTemplate.boundSetOps("name").add("曹操");
redisTemplate.boundSetOps("name").add("刘备");
redisTemplate.boundSetOps("name").add("孙权");
}
// 取值
@Test
public void getValue() {
Set set = redisTemplate.boundSetOps("name").members();
System.out.println(set);
}
// 删除其中一个value
@Test
public void removeValue() {
redisTemplate.boundSetOps("name").remove("孙权");
}
// 删除整个set
@Test
public void delValue() {
redisTemplate.delete("name");
}
}
TestList:有序
public class TestList {
@Autowired
private RedisTemplate redisTemplate;
@Test
/**
* 右压栈
*/
public void setValue1() {
redisTemplate.boundListOps("nameList1").rightPush("刘备");
redisTemplate.boundListOps("nameList1").rightPush("关羽");
redisTemplate.boundListOps("nameList1").rightPush("张飞");
}
// 取值
@Test
public void getValue1() {
List list = redisTemplate.boundListOps("nameList1").range(0, 10);
System.out.println(list);
}
// 左压栈
@Test
public void setValue2() {
redisTemplate.boundListOps("nameList2").leftPush("刘备");
redisTemplate.boundListOps("nameList2").leftPush("关羽");
redisTemplate.boundListOps("nameList2").leftPush("张飞");
}
// 取值
@Test
public void getValue2() {
List list = redisTemplate.boundListOps("nameList2").range(0, 10);
System.out.println(list);
}
// 查询某个元素的值
@Test
public void searchByIndex() {
String str = (String)redisTemplate.boundListOps("nameList2").index(1);
System.out.println(str);
}
// 删除
@Test
public void removeValue1() {
redisTemplate.boundListOps("nameList1").remove(1, "张飞");
}
}
TestHash:和Map差不多
public class TestHash {
@Autowired
private RedisTemplate redisTemplate;
// 设置值
@Test
public void setValue() {
redisTemplate.boundHashOps("nameHash").put("a", "唐僧");
redisTemplate.boundHashOps("nameHash").put("b", "悟空");
redisTemplate.boundHashOps("nameHash").put("c", "八戒");
redisTemplate.boundHashOps("nameHash").put("d", "沙僧");
}
// 获取所有的Keys
@Test
public void getKeys() {
Set keys = redisTemplate.boundHashOps("nameHash").keys();
System.out.println(keys);
}
// 获取所有的Values
@Test
public void getValues() {
List list = redisTemplate.boundHashOps("nameHash").values();
System.out.println(list);
}
// 根据Key获取Value
@Test
public void searchValueByKey() {
String str = (String)redisTemplate.boundHashOps("nameHash").get("b");
System.out.println(str);
}
// 移除某个小Key的值
@Test
public void removeByKey() {
redisTemplate.boundHashOps("nameHash").delete("c");
}
}