1、简介
1.1、特点
redis是一个开源的key-value存储系统,支持多种数据结构,包括:String,hashes,lists,sets和sorted sets。redis将数据存储于内存中,在内存不足的时候使用虚拟内存来保存数据,redis又两种持久化方案:
1、定时将当前缓存数据存到硬盘。(默认)
2、aof形式:把所有对redis 的操作命令存储到文件中,恢复时使用。
redis还支持主从复制,master写入,slave读取。redis是单线程的(保证原子性操作)。
1.2、与mybatis自带缓存对比
mybatis自带缓存存储于本机电脑内存,不能扩容,redis是集群式缓存,可以扩展。
2、redis集群介绍
redis是将数据存储到内存中,而我们电脑内存一般不大,所以可以搭建集群增大内存。
可以看到,redis集群没有统一的入口。
有如下特点:
1、所有节点互通(PING-PONG机制)
2、节点的fail是超过半数节点判断失效后才失效。
3、客户端与节点连接不需要通过中间层,直接连接即可。
4、redis可以预先设置好最大16384个槽,存放任意一个key-value的值时,根据CRC16(key)mod 16384的值决定放到哪一个槽中,二这些槽又是均匀分配到没有redis节点上的。
redis主从模式:
redis为了提高可用性,增加了主从模式,每个主节点分配一个从节点,从节点作为主节点的备份节点,挡主节点挂掉过后,从节点代替,如果没有从节点,主节点挂掉过后,集群便挂掉。
3、redis单机版及集群搭建
redis单机版和集群的搭建网上又很多教程讲的很详细,可以直接看着教程一步步走,我这里搭建了一个redis单机版和伪集群到虚拟机上,可以直接使用,下载地址:redis伪集群虚拟机
4、jedis连接测试
新建一个测试类,用来测试jedis与redis的连接:
@Test
public void TestJedis(){
Jedis jedis = new Jedis("192.168.156.11",6379);
jedis.set("test", "hello world");
String result = jedis.get("test");
System.out.println(result);
jedis.close();
}
代码中是我redis服务器的ip地址和端口号。
5、jedispool连接测试
新建一个测试类,用来测试jedispool与redis的连接:
@Test
public void TestJedisPool(){
JedisPool jedisPool = new JedisPool("192.168.156.11",6379);
Jedis jedis = jedisPool.getResource();
jedis.set("haha", "haha");
String resultString = jedis.get("haha");
System.out.println(resultString);
jedis.close();
jedisPool.close();
}
6、jedisClient连接单机版
测试类写好后,我们开始写操作redis的相关服务jedisClient接口,再写两个实现类,一个用于连接单机版,平时我们测试用,另一个用来连接集群,这样测试的时候就不用开那么多redis节点了。
jedisClient接口代码:
package com.taotao.jedis.service;
public interface JedisClient {
//Redis SET命令用于在Redis键中设置一些字符串值
String set(String key, String value);
//根据key去查询相应的值
String get(String key);
//判断key在Redis缓存中是否存在
Boolean exists(String key);
//设置key的过期时间
Long expire(String key, int seconds);
//Redis TTL 命令以秒为单位返回 key 的剩余过期时间
Long ttl(String key);
//Redis Incr 命令将 key 中储存的数字值增一
Long incr(String key);
/**
* Redis Hset 命令用于为哈希表中的字段赋值 。
* 如果哈希表不存在,一个新的哈希表被创建并进行 HSET 操作。
* 如果字段已经存在于哈希表中,旧值将被覆盖。
* @param key
* @param field
* @param value
* @return
*/
Long hset(String key, String field, String value);
//Redis Hget 命令用于返回哈希表中指定字段的值。
String hget(String key, String field);
//Redis Hdel 命令用于删除哈希表 key 中的一个或多个指定字段,不存在的字段将被忽略。
Long hdel(String key, String... field);
}
单机版实现类:
package com.taotao.jedis.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import com.taotao.jedis.service.JedisClient;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class JedisClientPool implements JedisClient {
@Autowired
private JedisPool jedisPool;
@Override
public String set(String key, String value) {
Jedis jedis = jedisPool.getResource();
String result = jedis.set(key, value);
jedis.close();
return result;
}
@Override
public String get(String key) {
Jedis jedis = jedisPool.getResource();
String result = jedis.get(key);
jedis.close();
return result;
}
@Override
public Boolean exists(String key) {
Jedis jedis = jedisPool.getResource();
Boolean result = jedis.exists(key);
jedis.close();
return result;
}
@Override
public Long expire(String key, int seconds) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.expire(key, seconds);
jedis.close();
return result;
}
@Override
public Long ttl(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.ttl(key);
jedis.close();
return result;
}
@Override
public Long incr(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.incr(key);
jedis.close();
return result;
}
@Override
public Long hset(String key, String field, String value) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hset(key, field, value);
jedis.close();
return result;
}
@Override
public String hget(String key, String field) {
Jedis jedis = jedisPool.getResource();
String result = jedis.hget(key, field);
jedis.close();
return result;
}
@Override
public Long hdel(String key, String... field) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hdel(key, field);
jedis.close();
return result;
}
}
编写applicationContext-jedis.xml文件,里面把注解打开,然后将jedispool和单机版实现类编写到xml文件中,方便spring容器初始化。
<!-- 开启注解 -->
<context:annotation-config/>
<!-- redis单机版 -->
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg name="host" value="192.168.156.11"/>
<constructor-arg name="port" value="6379"/>
</bean>
<bean id="jedisClientPool" class="com.taotao.jedis.service.impl.JedisClientPool"></bean>
<!-- redis集群版 -->
7、jedisClient连接集群
集群版实现类代码:
package com.taotao.jedis.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import com.taotao.jedis.service.JedisClient;
import redis.clients.jedis.JedisCluster;
public class JedisClientCluster implements JedisClient {
@Autowired
private JedisCluster jedisCluster;
@Override
public String set(String key, String value) {
return jedisCluster.set(key, value);
}
@Override
public String get(String key) {
return jedisCluster.get(key);
}
@Override
public Boolean exists(String key) {
return jedisCluster.exists(key);
}
@Override
public Long expire(String key, int seconds) {
return jedisCluster.expire(key, seconds);
}
@Override
public Long ttl(String key) {
return jedisCluster.ttl(key);
}
@Override
public Long incr(String key) {
return jedisCluster.incr(key);
}
@Override
public Long hset(String key, String field, String value) {
return jedisCluster.hset(key, field, value);
}
@Override
public String hget(String key, String field) {
return jedisCluster.hget(key, field);
}
@Override
public Long hdel(String key, String... field) {
return jedisCluster.hdel(key, field);
}
}
编写编写applicationContext-jedis.xml文件,将jedisCluster和集群版实现类编写到xml文件中。
<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
<constructor-arg>
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.156.11"/>
<constructor-arg name="port" value="7001"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.156.11"/>
<constructor-arg name="port" value="7002"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.156.11"/>
<constructor-arg name="port" value="7003"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.156.11"/>
<constructor-arg name="port" value="7004"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.156.11"/>
<constructor-arg name="port" value="7005"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.156.11"/>
<constructor-arg name="port" value="7006"/>
</bean>
</set>
</constructor-arg>
</bean>
<bean id="jedisClientCluster" class="com.taotao.jedis.service.impl.JedisClientCluster"></bean>
8、实际中缓存测试
实际中测试主要是在我们查询的时候需要添加缓存查询,缓存没有查到在通过mysql数据后,然后再存入缓存中。同时,每一次在数据库添加、修改、和删除都要把缓存中对应的数据给清理掉。
1、查数据时先查缓存:
public List<TbContent> getContentListByCid(long cid) {
//查询缓存
String liString = jedisClient.hget("INDEX_CONTENT", cid+"");
if(StringUtils.isNotBlank(liString)){
JavaType javaType = getCollectionType(ArrayList.class, TbContent.class);
try {
List<TbContent> tbList = (List<TbContent>)mapper.readValue(liString, javaType);
return tbList;
} catch (JsonParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JsonMappingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
TbContentExample example = new TbContentExample();
Criteria criteria = example.createCriteria();
criteria.andCategoryIdEqualTo(cid);
List<TbContent> list = tbContentMapper.selectByExample(example);
//存入缓存
try {
String jsonString = mapper.writeValueAsString(list);
jedisClient.hset("INDEX_CONTENT", cid+"", jsonString);
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
}
2、更新操作删除对应的缓存:
public List<TbContent> getContentListByCid(long cid) {
//查询缓存
String liString = jedisClient.hget("INDEX_CONTENT", cid+"");
if(StringUtils.isNotBlank(liString)){
JavaType javaType = getCollectionType(ArrayList.class, TbContent.class);
try {
List<TbContent> tbList = (List<TbContent>)mapper.readValue(liString, javaType);
return tbList;
} catch (JsonParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JsonMappingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
TbContentExample example = new TbContentExample();
Criteria criteria = example.createCriteria();
criteria.andCategoryIdEqualTo(cid);
List<TbContent> list = tbContentMapper.selectByExample(example);
//存入缓存
try {
String jsonString = mapper.writeValueAsString(list);
jedisClient.hset("INDEX_CONTENT", cid+"", jsonString);
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
}