什么是Redis

Redis:Remote Dictionary Server(远程字典服务器)。是完全开源免费的,用C语言编写的,遵守BSD协议,是一个高性能的(key/value)分布式内存数据库,基于内存运行并支持持久化的NoSQL数据库,是当前最热门的NoSQL数据库之一,也被人们称为数据结构服务器。

redis的特点

  • Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库系统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知综合性能最快的Key-Value DB。
  • Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存多种数据结构,此外单个value的最大限制是1GB,不像 memcached只能保存1MB的数据,因此Redis可以用来实现很多有用的功能,比方说用他的List来做FIFO双向链表,实现一个轻量级的高性能消息队列服务,用他的Set可以做高性能的tag系统等等。另外Redis也可以对存入的Key-Value设置expire时间,因此也可以被当作一 个功能加强版的memcached来用。
  • Redis是单进程单线程的,这样利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。
  • Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。

redis的优势

速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)

支持丰富数据类型,支持string,list,set,sorted set,hash

支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行

丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

redis的数据存储和读写模式

  • Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以redis具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。可通过设置最大使用内存,则数据已有记录数达到内存限值后不能继续插入新值。
  • redis支持主从的模式:Master会将数据同步到slave,而slave不会将数据同步到master。Slave启动时会连接master来同步数据。这个典型的分布式读写分离模型,利用master来插入数据,slave提供检索服务,有效减少单个机器的并发访问数量。

redis集群的缺陷及解决方案

  • 集群的读写分离模型通过增加Slave DB和Master DB的数量,整个集群的读和写的可用性都非常高。但是不管是Master还是Slave,每个节点都必须保存完整的数据,如果在数据量很大的情况下,集群的扩展能力还是受限于单个节点的存储能力,而且对于Write-intensive类型的应用,读写分离架构并不适合。
  • 数据分片模型用于解决读写分离模型的缺陷,可以将每个节点看成都是独立的master,然后通过业务实现数据分片。将每个master设计成由一个master和多个slave组成的模型。

redis数据类型及常用语句:

string:
String是redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。String类型是二进制安全的:意思是redis的String可以包含任何数据,比如jpg图片或者序列化的对象。String类型是redis最基本的数据类型,一个redis中字符串value最多可以是512M。
	incr key              ==>某个键自增1
	decr key              ==>某个键自减1
	incrby key k          ==>某个键自增k
	decrby key k          ==>某个键自减k
	set key value         ==>不论键是否存在都加(insert and update)
	setnx key value       ==>键不存在才加进去(insert)
	set key value xx      ==>键存在才加进去(update)
	mget key1 key2 key3   ==>获取多个key的value
	mset key1 value1 key2 value2 key3 value3    ==>设置多个键值对
	getset key newvalue      ==>给这个key赋新的值,该条命令返回的是旧的value
	append key value         ==>将value追加到旧的value,以value1,value2的形式
	strlen key               ==>返回key对应的value的字符串长度(UTF8中,一个中文占两位)
	incrbyfloat key f        ==>某个键自增f,f可以为flsoat类型
	getrange key start end   ==>得到对应的value的start到end之间的值
	setrange key index value ==>指定index位置设定值
hash:
Redis hash是一个键值对集合。Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。类似java里面的Map<String,Object>
	hget key filed        ==>获取key的filed的value
	hset key filed value  ==>设置key的filed的value
	hdel key filed        ==>删除key的filed
	hgetall key           ==>获取key的所有filed和对应的value
	hvals key             ==>获取key对应的所有的filed的value
	hkeys key             ==>获取key对应的所有的filed
	hexists key filed     ==>判断某个key是否存在某个filed
	hlen key              ==>获取key的filed的数量
	hmget key filed1 filed2 filed3        ==>获取某个key一批filed的value
	hmset key filed1 value1 filed2 value2 ==>设置某个key一批filed的value
list:
Redis列表是简单的字符串列表,按照插入顺序排序,你可以添加一个元素到列表的头部(左边)或者尾部(右边)。它的底层实际是个链表。
	lpush key value1 value2 value3        ==>从列表左端插入值
	rpush key value1 value2 value3        ==>从列表右端插入值
	linsert key before|after value newValue
	lpop key                   ==>从左边弹出一个value
	rpop key                   ==>从右边弹出一个value
	lrem key count value       ==>count=0 删除对应的value中所有的value值
	                           ==>count>0 从左到右删除对应的value中的count个value值
       					       ==>count<0 从右到左删除对应的value中的count个value值
	ltrim key start end        ==>保留key对应的value的第start到end个
	lrange key start end       ==>获取key对应value的第start到end个
	lindex key index           ==>获取key对应value的第index的value
	llen key                   ==>获取key对应的value的长度
	lset key index newValue    ==>设置key对应的value的第index位为newValue
	blpop key timeout          ==>左弹出阻塞timeout间段
	brpop key timeout          ==>右弹出阻塞timeout间段
set:
Redis的Set是String类型的无序集合,它是通过HashTable实现的。
	sadd key value1 value2     ==>添加key对应的value值,value若重复则失败
	sinter key1 key2 key3      ==>集合交集
	sdiff key1 key2 key3       ==>集合不同的集合
	sunion key1 key2 key3      ==>集合并集
	scard key                  ==>集合大小
	sismember key value        ==>存在1,不在0
	srandmember key count      ==>随机选出集合中count个元素
	spop key                   ==>随机弹出一个元素,弹出后,该元素在集合中消失
	smembers key               ==>返回集合中所有元素
zset:
Redis zset和set一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数(score)。Redis根据score进行从小到大的排序。zset的成员唯一的,但分数(score)却可以重复。
	 zadd key score value      ==>添加key对应的value值,并且附上权值score
	 zrem key value1 value2    ==>删除value值
	 zscore key value          ==>返回value对应的权值
	 zincrby key increScore value    ==>给key对应的value集合中的value对应的score增加increScore的值
	 zcard key                 ==>返回集合总数
	 zrank key value           ==>返回集合中value的排名
	 zrange key start end [withscores]                  ==>获取排名start到end之间的value集合
	 zrangebyscore key minScore maxScore [withscores]   ==>获取权值在minScore到maxScore之间的value集合
	 zcount key minScore maxScore                       ==>获取分数在minScore到maxScore之间的value集合的个数
	 zremrangebyrank key start end                      ==>删除排名start到end之间的value集合
	 zremrangebyscore key minScore maxScore             ==>删除分数在minScore到maxScore之间的value
none:
redis的详细命令文档 http://doc.redisfans.com/

Redis的安装和启动(Linux)

安装

这里我下载的是 redis-3.2.1.tar.gz

wget http://download.redis.io/releases/redis-5.0.5.tar.gz

解压

tar xzf redis-5.0.5.tar.gz

进入目录,安装

cd redis-5.0.5
make
make install PREFIX=/usr/local/redis-5.0.5
配置环境变量

启动redis服务器(推荐指定配置文件启动):

在redis-5.0.5目录下,建立一个config的文件夹,把默认的redis.conf拷贝到这个目录下
去掉redis.conf中的注释和空行,并复制为redis-6380.conf

grep -v “^#” redis.conf | grep -v “^$” >> redis-6380.conf

将daemonize no改为daemonize yes
将port 6379改为port 6380

运行该配置文件

redis-server redis-6380.conf

查看redis服务器是否运行(看到6380端口的redis进程存在即已运行)

ps aux | grep redis

redis客户机连接

redis-cli -h 127.0.0.1 -p 6380

关闭redis服务器

redis-cli -p 6380 shutdown

SSM整合redis

有一个搭好初步框架的SSM项目(这里不多做介绍)

配置pom.xml中加入依赖

<!--redis相关 -->
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>1.8.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>

建立redis.properties文件,设置redis连接参数

redis.host=***.***.***.***   # 你的redis的地址
redis.port=****              # 你的redis的端口
redis.pass=****              # 你的redis的密码
redis.maxIdle=200
redis.maxActive=1024
redis.maxWait=10000
redis.testOnBorrow=true

配置redis文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd ">

    <!-- 连接池基本参数配置,类似数据库连接池 -->
    <context:property-placeholder location="classpath:redis.properties" ignore-unresolvable="true"/>

    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxTotal" value="${redis.maxActive}"/>
        <property name="maxIdle" value="${redis.maxIdle}" />
        <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>
        <property name="port" value="${redis.port}"></property>
         <property name="password" value="${redis.pass}"></property>
        <property name="poolConfig"  ref="poolConfig"></property>
    </bean>

    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="jedisConnectionFactory" />

        <!-- 序列化方式 建议key/hashKey采用StringRedisSerializer -->
        <property name="keySerializer">
            <bean
                    class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="valueSerializer">
            <bean
                    class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
        </property>
        <property name="hashKeySerializer">
            <bean
                    class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="hashValueSerializer">
            <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
        </property>
        <!-- 开启REIDS事务支持 -->
        <property name="enableTransactionSupport" value="false" />
    </bean>

    <!-- 对string操作的封装 -->
    <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
        <constructor-arg ref="jedisConnectionFactory" />
        <!-- 开启REIDS事务支持 -->
        <property name="enableTransactionSupport" value="false" />
    </bean>

</beans>

applicationContext.xml中注入redis.xml的配置

<import resource="classpath*:/spring/spring-redis.xml"/>

我的项目在resources下建立spring的文件夹,将spring的其他配置放在里面

写一个测试方法验证redis的连通性

/**
 * Created by Administrator on 2020-1-23.
 */
@RunWith(SpringJUnit4ClassRunner.class)
//告诉junit spring配置文件
@WebAppConfiguration
@ContextConfiguration({"classpath:applicationContext.xml"})
public class TestDAO {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void test(){
        try{
            redisTemplate.opsForValue().set("test", "测试");
            System.out.println("value:"+redisTemplate.opsForValue().get("test"));
        }catch(Exception e){
            System.out.println("Redis-error");
        }
    }
}

完成redis的工具类

这里仅以缓存中构建key为例,redisTemplate的API可以参考博客

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * redis工具类
 */
@SuppressWarnings("unchecked")
public class RedisUtil {
    
    @Autowired
    private static RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private static StringRedisTemplate stringRedisTemplate;

    private static String CACHE_PREFIX;
    
    /**
     * 构建缓存key值
     * @param key   缓存key
     * @return
     */
    private static String buildKey(String key) {
        if (CACHE_PREFIX == null || "".equals(CACHE_PREFIX)) {
            return key;
        }
        return CACHE_PREFIX + ":" + key;
    }
}

去自己工程中根据自己的业务逻辑编写代码

参考博文:https://www.jianshu.com/p/9e144509bdcb