Bootstrap

Redis知识总结(四万字)

一、Redis的概述

1.1 NoSQL的简介

1.1.1 NoSQL为什么会出现

从功能角度来讲,出现了各种编程语言

c语言,c++, java,scala,php,python等

从扩展角度来讲,对编程语言进行统一规范,设计各种接口,出现了各种编程语言的框架

structs,hibernate,mybatis,tomcat,RDBMS等

由于应用的请求数量越来越多,存储的数据越来越多,数据种类也越来越多,就出现了性能问题,为了解决性能问题

nginx,NoSql,MQ等

1.1.2 什么是NoSQL

1. NoSql, 是Not only Sql的简写,泛指非关系型数据库。
2. 为了解决高并发、高可扩展、高可用、大数据存储问题而产生的另一种数据库解决方案
3. 是RDBMS的良好补充,并不能取代RDBMS。(各有各的应用场景,RDBMS适合OLTP,Nosql适合OLAP)
4. NoSQL数据库基本上也都是基于内存的,所以访问速度也很快。

1.1.3 NoSQL的分类

#第一类:键值(Key-Value)存储数据库
	
	相关产品: Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB
   典型应用: 内容缓存,主要用于处理大量数据的高访问负载。
   数据模型:一系列键值对
      优势:快速查询
      劣势:存储的数据缺少结构化

#第二类  列存储数据库
  
   相关产品:Cassandra, HBase, Riak
	典型应用:分布式的文件系统
	数据模型:以列簇式存储,将同一列数据存在文件系统中
	优势:查找速度快,可扩展性强,更容易进行分布式扩展
	劣势:功能相对局限

#第三类:文档型数据库

	相关产品:CouchDB、MongoDB
	典型应用:Web应用(与Key-Value类似,Value是结构化的)
	数据模型:一系列键值对
	优势:数据结构要求不严格
	劣势:查询性能不高,而且缺乏统一的查询语法

#第四类:图形(Graph)数据库
	
	相关数据库:Neo4J、InfoGrid、Infinite Graph
	典型应用:社交网络
	数据模型:图结构
	优势:利用图结构相关算法。
	劣势:需要对整个图做计算才能得出结果,不容易做分布式的集群方案。

1.2 Redis的简介

1.2.1 Redis的介绍

1. redis是一个c语言开发的,开源的,基于内存的NoSql数据库。也可以用作消息缓存系统(对比kafka)
2. 提供了多种数据结构支持
     strings:字符串
     hashes:散列
     lists:列表
     sets:集合
     sorted sets:带范围查询的有序集合, 
     bitmaps:位图类型
     hyperloglogs: 超日志
     geospatial:地理空间索引
     streams:流
3.  Redis内置了副本、Lua 脚本、LRU 驱逐、事务和不同级别的磁盘持久方式,
4.  可以通过Redis Sentinel和Redis Cluster的自动分区提供高可用性
5. 也可以对数据结构进行原子操作(说白了,就是对数据结构进行普通的CRUD)

1.2.2 Redis的应用场景

#1  缓存(数据查询、短连接、新闻内容、商品内容等等)。
		这种应用场景的使用是最多的

#2 分布式集群架构中的session分离。

#3 聊天室的在线好友列表。

#4 任务队列。(秒杀、抢购、12306等等)

#5 应用排行榜。

#6 网站访问统计。

#7 数据过期处理(可以精确到毫秒)

1.2.3 Redis的特性

1. 访问速度快,原因是Redis基于内存存储
2. Redis也支持持久化操作,而且有两种方式,一种方式是dump到磁盘,一种方式是AOF
   dump到磁盘:  就是存储内存中的具体数据
   AOF:   除了存储具体数据外,还存储操作类型,比如是insert,delete,update等
3. Redis也支持集群模式,可以扩展多个服务节点
4. Redis相较于其他的缓存工具,支持的数据类型是非常丰富的。

二、Redis的安装部署

2.1 Redis的官网和下载

英文官网:https://redis.io/
中文官网:http://www.redis.cn/
下载:https://download.redis.io/releases/xxxxx.tar.gz

2.2 Redis的安装部署

2.2.1 注意事项:

1. 一般都是安装在linux系统上
2. 又因为c语言开发的,所以源码安装时,需要c语言环境

   yum install gcc-c++

2.2.2 安装步骤

步驟1) 检查安装c语言环境

[root@qianfeng01 ~]#  yum install gcc-c++

步骤2)上传、解压、更名

[root@qianfeng01 ~]# tar -zxvf redis-4.0.14.tar.gz -C /usr/local/
[root@qianfeng01 ~]# cd /usr/local/
[root@qianfeng01 local]# mv redis-4.0.14/ redis

步骤3)编译

[root@qianfeng01 local]# cd redis
[root@qianfeng01 redis]# make 

步骤4)安装

[root@qianfeng01 redis]# make install PREFIX=/usr/local/redis

注意:此时在redis目录下,就会出现bin目录

步骤5)配置环境变量

[root@qianfeng01 redis]# vim /etc/profile
..........省略...........
#redis environment
export REDIS_HOME=/usr/local/redis
export PATH=$PATH:$REDIS_HOME/bin
[root@qianfeng01 redis]# source /etc/profile

#查看版本号
[root@qianfeng01 redis]# redis-cli --version

2.3 Redis服务的启动和关闭

2.3.1 启动方式

方式1)前台启动

只需要在命令行上输入redis-server脚本即可

[root@qianfeng01 redis]# redis-server

注意:由于是前台进程,如果ctrl+c了,就直接停止服务了。 所以不经常用

方式2)后台启动

#1: 将redis里的redis.conf拷贝到bin目录下
[root@qianfeng01 redis]# cp redis.conf bin/
#2: 修改bin下的redis.conf文件
[root@qianfeng01 bin]# vim redis.conf 
...省略...
 134 # By default Redis does not run as a daemon. Use 'yes' if you need it.
 135 # Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
 136 daemonize yes          <== 将no改为yes
 
#启动服务, 带上配置文件 
[root@qianfeng01 bin]# redis-server /usr/local/redis/bin/redis.conf

查看进程

[root@qianfeng01 ~]# ps -ef | grep redis
root      31713      1  0 10:37 ?        00:00:00 redis-server 127.0.0.1:6379
root      31771  19391  0 10:38 pts/0    00:00:00 grep --color=auto redis

2.3.2 关闭方式

方式1)正规关闭方式

[root@qianfeng01 ~]# redis-cli -h <ip地址或者主机名> shutdown

方式2)kill掉

[root@qianfeng01 ~]# kill -9  pid

2.4 如何连接redis服务

2.4.1 命令行工具

[root@qianfeng01 ~]# redis-cli -h <主机ip或主机名> -p <端口号>

reg:
[root@qianfeng01 ~]# redis-cli -h qianfeng01 -p 6379

默认情况:
[root@qianfeng01 ~]# redis-cli 
连接的是127.0.0.1

小贴士:

如果想要远程连接,需要将redis.conf里bind 127.0.0.1 修改为主机名 或者注释掉。
1. 如果修改为主机名,那么再连接时,一定要用到主机名,否则连不上
2. 如果是注释掉,可以本地连接,也可以远程连接。

2.4.2 Redis桌面管理工具

1. 双击安装即可
2. 配置参数:
	Name: 连接名称,随便写
	Host: 服务的ip或者host
	Port: 端口号6379
	Auth: 密码

注意:如果想要远程连接redis,需要修改redis.conf配置文件

方式1: 将69行对应的 bind 127.0.0.1 修改成主机名或者是ip
       即:
       bind qianfeng01
       或者
       bind 192.168.10.101
方式2: 注释掉即可

2.4.3 编程语言连接

1)说明

Redis不仅是使用命令来操作,也可以使用编程语言调用相关API接口进行连接。比如java、C、C#、C++、php、Node.js、Go等。

在官方网站里列一些Java的客户端api,有Jedis、Redisson、Jredis、JDBC-Redis等
官方推荐使用Jedis和Redisson。 在企业中用的最多的就是Jedis,下面我们就重点学习下Jedis。 

Jedis同样也是托管在github上,地址:httpsRedis.assets//github.com/xetorthio/jedis

2)pom.xml

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.0.0</version>
</dependency>

3)单线程连接方式

小贴士:需要将redis.conf里的protected-mode的no改为yes,即关闭保护模式。

package com.qf.redis.day01;

import redis.clients.jedis.Jedis;

/**
 * 单线程连接redis
 */
public class RedisDemo01 {
   
    public static void main(String[] args) {
   
        /**
         * Jedis(String host,int port)
         */
        Jedis jedis = new Jedis("qianfeng01", 6379);

        //调用ping指令 向远程主机发送信息,验证网络通信是否正常,返回pong 表示畅通
        String ping = jedis.ping();
        System.out.println(ping);

        //设置字符串类型的一个键值对,
        String setAck = jedis.set("girlfriend", "gaoyuanyuan");
        System.out.println(setAck);

        //从redis中获取girlfriend对应的value值
        String getAck = jedis.get("girlfriend");
        System.out.println(getAck);


        jedis.close();
    }
}

4)线程池连接方式

package com.qf.redis.day01;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
 * 使用线程池连接redis
 */
public class RedisDemo02 {
   
    public static void main(String[] args) {
   
        /**
         * 创建一个线程池对象
         * 构造器:
         *     JedisPool(String host,int port)
         *     JedisPool(GenericObjectPoolConfig config,String host)
         */
        GenericObjectPoolConfig config = new GenericObjectPoolConfig();
        config.setMaxTotal(20); //设置线程池中的最大值
        config.setMaxIdle(7);  //设置线程池中的最大空闲连接数
        config.setMinIdle(5);  //设置线程池中的最小空闲连接数
        config.setMaxWaitMillis(5000); //设置超时时间,单位毫秒
        JedisPool pool = new JedisPool(config, "qianfeng01");

        //从池子中获取一个具体的连接对象
        Jedis jedis = pool.getResource();

        //设置键值对
        String set = jedis.set("hobby", "movie");
        System.out.println(set);

        //获取key对应的value
        String hobby = jedis.get("hobby");
        System.out.println(hobby);
        jedis.close();// 将连接归还到连接池中
    }
}

2.5 Redis的密码策略

进入redis.conf文件,找到500行左右,解开注释,设置密码,修改后别忘记重启服务

# others with access to the host running redis-server.
#
# This should stay commented out for backward compatibility and because most
# people do not need auth (e.g. they run their own servers).
#
# Warning: since Redis is pretty fast an outside user can try up to
# 150k passwords per second against a good box. This means that you should
# use a very strong password otherwise it will be very easy to break.
#
requirepass 123123    <==  解开注释,设置密码

# Command renaming.
#
# It is possible to change the name of dangerous commands in a shared
# environment. For instance the CONFIG com

连接:需要使用-a 来设定密码

[root@qianfeng01 bin]# redis-cli -h qianfeng01 -p 6379 -a 123123

程序中如下设置:

 jedis.auth("123123");

2.6 redis的常规操作

2.6.1 库操作

1. redis的默认的db的个数是16个。id从0到15
2. 切换数据库
	select dbid
3. 清空当前数据库(慎用)
	flushdb
4. 清空所有的数据库(慎用)
	flushall

2.6.2 Redis的键

1. #根据匹配模式查询相关的key
   keys *   #查询所有的key
   keys ?O*   #查询第二个字符是O的key
2. dbsize     #查看当前库下所有的key的个数
3. exists key   #判断某一个key是否存在,  0表示不存在,1表示存在
4. type key    #查看key的类型
5. del key   #删除某一个key    1 表示删除成功  0表示删除失败
6. unlink key #删除某一个key(非阻塞删除) 
	 #仅将key从keyspace元数据中删除,真正的删除会在后续中异步删除   (先奏后斩的意思)
7. expire key seconds     #设置key的存活时间
8. persist key    #清除key的存活时间,  已经过期的清除没有意义
9. ttl key       #查看key的存活时间    -2表示过期  -1 表示永不过期

小故事

6379这个端口号,来源于一个意大利歌女的名字  merz

三、Redis的类型

Redis在存储数据时,都是以键值对的形式存储的,这个key的作用是用于指向value的,可以通过这个key获取具体的value值。我们所说的丰富的数据类型是针对于value来说的。key只是用来做映射关系。

那么key的长度是越长越好?还是越短越好?

都不是,尽量做到见名知意。

比如存储身份证是xxxxx1901xxxx的张三的这个人的爱好
set  xxxxx1901xxxx-zhangsan-hobbys   book  movie   eat 

太长占内存
太短的话:做不到见名知意   

3.1 Redis的五大常用类型

3.1.1 字符串类型

3.1.1.1 介绍
这是redis中的最简单类型。如果你只用这种类型,Redis就像一个可以持久化的memcached服务器(注:memcache的数据仅保存在内存中,服务器重启后,数据将丢失)。

由于 Redis 的键是字符串,所以当我们也使用字符串类型作为值时,我们是在将一个字符串映射到另一个字符串。字符串数据类型可用于许多用例,例如缓存 HTML 片段或页面。

应用场景:  可以将内存中的对象,进行存储到redis中
3.1.1.2 命令行常用指令
set指令的语法格式:set key value [EX seconds] [PX milliseconds] [NX|XX]
     EX: KV的存活时间,单位是秒
     PX: KV的存活时间,单位是毫秒
     NX: K不存在时,会设置成功
     XX: K已经存在时,会覆盖
get指令的语法格式:
	 get key
qianfeng01:6379[1]> set city changchun EX 100 NX
OK
qianfeng01:6379[1]> keys *
1) "city"
2) "word"
qianfeng01:6379[1]> set city beijing EX 100 NX    <==  会失败,因为city已经存在
(nil)
qianfeng01:6379[1]> get city
"changchun"
qianfeng01:6379[1]> set city beijing XX    <==  会成功,因为city已经存在
OK
qianfeng01:6379[1]> get city
"beijing"
qianfeng01:6379[1]>
qianfeng01:6379[1]> append city shanghai   <==  在key对应的原有的value上追加字符串
(integer) 15
qianfeng01:6379[1]> get city
"beijingshanghai"
qianfeng01:6379[1]> set num 1
OK
qianfeng01:6379[1]> decr num         <==  递减1   要求 value的类型是整形
(integer) 0 
qianfeng01:6379[1]> DECRBY num 5     <==  递减5   指定步长
(integer) -5
qianfeng01:6379[1]> get city
"beijingshanghai"
qianfeng01:6379[1]> GETRANGE city 0 2   <==  获取指定坐标之间的字符串,是一个闭区间
"bei"
qianfeng01:6379[1]> GETSET city shenyang    <==  覆盖值,并返回原有的值
"beijingshanghai"
qianfeng01:6379[1]> get num
"-5"
qianfeng01:6379[1]> incr num                <==  自增+1
(integer) -4
qianfeng01:6379[1]> INCRBY num 2           <==  指定自增的步长
(integer) -2
qianfeng01:6379[1]> mset username zhangsan age 23 gender f isMarry false    <==  设置多对KV
OK
qianfeng01:6379[1]> mget username age gender isMarry num     <== 获取多个Key的value值
1) "zhangsan"
2) "23"
3) "f"
4) "false"
5) "-2"
3.1.1.3 代码演示
package com.qf.redis.day01;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;

import java.util.List;

/**
 * 练习Redis的字符串类型的API
 */
public class RedisDemo03_String {
   
    public static void main(String[] args) {
   
        getOfString();
    }
    //set命令的测试
    public static void setOfString(){
   
        Jedis jedis = new Jedis("qianfeng01", 6379);
        jedis.auth("123123");


        jedis.set("classno","sz2103");
        SetParams setParams = new SetParams();
        setParams.ex(100); //设置存活时间,单位是秒
        //setParams.px(50000);  //设置存活时间,单位是毫秒
        jedis.set("teacher","michael",setParams);
        jedis.setnx("teacher1","anjinglaoshi");
        jedis.append("city"," is good");
        jedis.incr(
;