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深入学习 redis入门_ide


可以看到,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;  
    }