Redis学习笔记

博主 1126 2020-07-18

参考视频Redis教程-最新Redis视频教程-不得不精Redis

第一章 NoSQL

1.1 什么是NoSQL

NoSQL= Not Only SQL(不仅仅是SQL),也解释为non-relational(非关系型数据库),在NoSQL数据库中数据之间是无联系的,无关系的,数据的结构是松散的,可变的

1.2 关系型数据库的问题

互联网应用特点:访问量巨大,高并发,高可用,海量数据
关系型数据库的瓶颈:
image.png

1.3 NoSQL的优势

1)大数据量,高性能
2)灵活的数据模型
3)高可用
4)低成本

1.4 NoSQL的劣势

1)无关系,数据之间无联系
2)不支持标准的SQL,没有公认的NoSQL标准
3)没有关系型数据库的约束,大多数也没有索引的概念
4)没有事务,不能依靠事务实现ACID
5)没有丰富的数据类型(数值,日期,字符,二进制,大文本等)

第二章 Redis安装和使用

Redis是当今非常流行的基于KV结构的作为Cache使用的NoSQL数据库

2.1 Redis介绍

image.png

2.2 mac安装redis

参考
mac安装redis

2.3 linux安装redis

参考
linux安装redis

配置好服务以后使用systemctl命令管理redis服务
systemctl start redis.service #启动redis服务

systemctl stop redis.service #停止redis服务

systemctl restart redis.service #重新启动服务

systemctl status redis.service #查看服务当前状态

systemctl enable redis.service #设置开机自启动

systemctl disable redis.service #停止开机自启动

2.4 配置redis可以远程访问

修改 redis.conf
注释掉bind 127.0.0.1
修改保护模式protected-mode为no
(记得配置服务器安全组)
然后使用 ./redis-cli -h ip -p port 远程连接redis
输入密码auth password

2.5 基本操作命令

1)沟通命令ping
2)dbsize 返回有多少个kv对
3)可以在redis.conf配置文件修改默认数据库个数,默认为16个
databases 16
4)select db 选择库,库从0号开始
5)flushdb 删除当前库的数据
6)exit,quit退出客户端

2.6Redis的Key的操作命令

1)keys
语法:keys pattern
作用:查找所有符合模式pattern的key,pattern可以使用通配符
通配符:
*:表示0-多个字符
?:表示单个字符
eg:
keys * 显示所有key
keys wo??d

2)exists
语法:exists key[key...]
作用:判断key是否存在
返回值:整数,存在key返回1,其他返回0,使用多个key,返回存在的key的数量
eg: exists k1 k2

3)expire
语法:expire key seconds
作用:设置key的生存时间,超过时间,key自动删除,单位是秒
返回值:设置成功返回数字1,其他情况返回0
eg: expire redlight 5

4)ttl
语法: ttl key
作用:以秒为单位,返回key的剩余生存时间(ttl:time to live)
返回值:
-1:没有设置key的生存时间,key永不过期
-2:key不存在
其他数字:key的剩余时间,以秒为单位

5)type
语法:type key
作用:查看key所存储值得数据类型
返回值:字符串所表示的数据类型
none(key不存在)
string(字符串)
list(列表)
set(集合)
zset(有序集)
hash(哈希表)

6)del
语法:del key[key...]
作用:删除存在的key,不存在的key忽略
返回值:数字,删除的key的数量

2.7 Redis的5种数据类型

1)字符串类型string
"username"="root"

2)hash

相当于Map<String, Map<String, String> >类型
引入field和key概念的区分

3)list
字符串列表,可以指定添加的元素到列表的头部或者尾部

4)set
set是string类型的无序集合,集合成员是唯一的

5)zset
有序集合,集合成员不重复,唯一

第三章 Redis数据类型操作命令

3.1 string类型

3.1.1 基本命令
1)set
set key value
2)get
get key
3)incr
incr key
如果key存在,则+1并返回;如果key不存在,创建一个key,value为0,再+1并返回
incr具有原子性
4)decr
decr key 减一操作
具有原子性
5)append
append key value
如果key存在,则将value追加到key原来的value后面
如果key不存在,则创建key

3.1.2 常用命令
1)strlen
strlen key
返回长度
2)getrange
getrange key start end
获取key中字符串值从start开始到end结束的子串,包括start和end,负数表示从字符串的末尾开始,-1表示最后一个字符,-2表示倒数第二个字符
3)setrange
setrange key offset value
用value覆盖key的存储的值,从offset开始,不存在的key当做空白字符串
返回修改后的字符串的长度
4)mset
mset key value[key value...]
同时创建多个key-value 对
5)mget
mget key[key...]
同时获取多个key的值,返回列表,返回值列表顺序和输入key的顺序相同,不存在的key返回nil

3.2 hash类型

redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象
3.2.1 基本命令
1)hset
hset key field value[field value]
(我可以设置多个值,可能是新版redis改进了,已知4.0不可以创建多个field)
将hash的key中的域field的值设为value,如果key不存在,则新建hash;如果有field,则覆盖value
返回值:
如果field是hash表中新field,且设置成功,返回新建的field的数量
如果field已经存在,旧值覆盖新值,返回0
2)hget
hget key field
返回hash中key中给定的field的值
返回nil代表key不存在或者field不存在
3)hmset
hmset key field value[field value]
设置一个hash,多个field和value
4)hmget
hmget key field[field]
获取一个hash中多个field的值
5)hget all
hget all key
返回hash所有的field和value
6)hdel
hedl key field
返回删除成功的数量
3.2.2 常用命令
1)hkeys
hkeys key
返回hash中所有的field
2)hvals
hvals key
返回hash 中所有的value
3)hexists
hexists key field
检查指定key中是否存在field
存在返回1,其他返回0

3.3 列表list

Redis list是简单的字符串列表,按照插入顺序排序,可以添加新元素到列表头或尾
3.3.1 基本命令
1)lpush
lpush key value[value...]
将一个或多个value插入列表左侧,从左到右的顺序依次插入到表头
返回值:数字,新列表的长度
eg: lpush mylist a b c
添加后列表为 ["c", "b", "a"...]
2)rpush
rpush key value[value...]
将一个或多个value插入列表右侧,从左到右的顺序依次插入到表尾
返回值:数字,新列表的长度
eg: rpush mylist a b c
添加后列表为 [..."a", "b", "c"]
3)lrange
lrange key start stop
获取列表key中指定区间内的元素,0表示列表的第一个元素,以1表示列表的第二个元素;start,stop是列表的下标值,也可以是负数的下标,-1表示列表的最后一个元素,-2表示列表的倒数第二个元素,以此类推。start,stop超出列表的返回不会出现错误
返回值:指定区间的列表
4)lindex
lindex key index
获取key中指定index的成员,同样可以为负数
5)llen
llen key
求列表成员的个数

3.3.2 常用命令
1)lrem
lrem key count value
根据参数count的值,移除列表中与参数value相等的元素,count>0,从列表的左侧开始向右移除;count<0从列表的尾部开始移除;count=0移除表中所有与value相等的值。
返回值:数值,移除的元素个数
eg:lrem alist 2 "java"
从alist左侧开始向右,删除2个"java"
2)lset
lset key index value
将列表key下标为index的值设为value
3)linsert
linsert key BOFORE|AFTER pivot value
将值value插入到列表key当中位于值pivot之前或之后的位置。key不存在,pivot不在列表中,不执行任何操作
返回值:命令执行成功,返回新列表的长度。没有找到pivot返回-1,key不存在返回0

3.4 集合类型set

3.4.1 基本命令
1)sadd
sadd key member[member...]
将一个或多个member元素加入到集合key当中,已经存在于集合的member元素将被忽略,不会再加入
返回值:加入到集合的新元素的个数,不包括被忽略的元素
eg:sadd sql insert delete update
2)smembers
smembers key
获取集合key中的所有成员元素,不存在的key视为空集合
3)sismember
sismember key member
返回1说明有,返回0说明没有
4)scard
scard sql
获取集合的元素个数
5)srem
srem key member[member..]
删除集合key中的一个或多个元素
返回删除成功的个数

3.4.2 重用命令
1)srandmember
srandmember key[count]
只提供key,随机返回集合中一个元素,元素不删除,依然在集合中;提供了count时,count为正数,返回包含count个数元素的集合,集合元素各不相同,count是负数,返回一个count绝对值的长度的集合,集合中元素可能会重复多次
2)spop
spop key[count]
删除count个数的元素
返回被删除的元素列表

3.5 有序集合zset

有序集合按照分数从小到大排序,分数相同按member的字典序

3.5.1 基本命令
1)zadd
zadd key score member[score member...]
将一个或多个member元素及其score值加入到有序集合key中,如果member存在集合中,则更新值;score可以使整数或浮点数
返回值:数字,新添加元素个数
eg:zadd studentscore 80 zhangsan 92 lisi 75 wangwu
2)zrange
zrange key start stop[WITHSCORES]
查询有序集合,指定区间内的元素,集合元素按score值从小到大大来排序,start和stop都是从0开始。0是第一个元素,1是第二个元素,以此类推,-1表示最后一个元素。WITHSCORES选项让score和value一同返回
返回值:自定区间内的成员集合
eg:zrange studentsscore 0 -1
3)zrevrange
zrevrange key start stop[WITHSCORES]
按照分数从大到小显示
4)zrem
zrem key member[member]
返回被删除的成员个数
5)zcard
zcard key
返回成员个数

3.5.2 常用命令
1)zrangebyscore
zrangebyscore key min max[WITHSCORES][LIMIT offset count]
获取有序集key中,所有score值介于min和max之间(包括min和max)的成员,有序成员是按递增(从小到大)排序。
min,max是包括在内的。使用符号左括号'('表示不包括,min,max可以用-inf,+inf表示最小和最大
limit用来限制返回结果的数量和区间,offset是起始位置(从0开始),count是成员数量
返回指定区间的集合数据
eg:zrangebyscore sal (2000 5000 WITHSCORES 查询2000<score<=5000的成员
zrangebyscore sal 3000 +inf WITHSCORES 查询3000<=score 的成员
2)zrevrangebyscore
zrevrangebyscore key max min[WITHSCORES][LIMIT offset count]
按score从大到小返回指定区间的集合数量
3)zcount
zcount key min max
返回score在该区间范围内成员个数

第四章 高级话题

4.1 Redis事务

4.1.1 什么是事务

事务是指一系列操作步骤,这一系列的操作步骤,要么完全执行,要么都不执行
Redis事务是一组命令的集合,至少是两个或两个以上的命令,redis事务保证这些命令会被执行时中间不会被其他任何操作打断。

4.1.2 事务操作的命令

1)multi
image.png
2)exec
image.png
3)discard
image.png
4)watch
image.png
5)unwatch
image.png

4.1.3 事务的实现

1)正常执行事务
image.png

返回结果
image.png
2)事务中的命令语法出错
例如事务中出现语法错误
incr k1 k2
在exec后,事务被放弃执行
image.png
3)事务中的命令语法无错,执行时出错
image.png
返回结果:
image.png
发现仍然提交了命令,没有回滚
4)主动放弃事务
使用discard放弃事务
5)Redis的watch机制
image.png

4.2 持久化

4.2.1 持久化概述
image.png

4.2.2 持久化方式
1)RDB方式
image.png
如何实现:
image.png
image.png
以上定义的3个规则满足1条就可以进行快照,可以自定义多条规则


配置步骤
image.png

2)AOF方式
image.png
image.png

4.3 主从复制

image.png

Redis集群
主redis又称为master,从redis称为slave
主redis主要用于写操作,从redis用于读操作,完成读写分离

4.3.1 主从复制-读写分离
主从复制实现:
image.png
image.png
image.png
image.png
image.png
image.png
使用命令info replication查看主从关系


容灾处理
image.png
原主机恢复后,重新挂至现有主机,作为从服务器使用

4.3.2 高可用Sentinel哨兵
image.png
image.png

哨兵工作模式:
image.png
哨兵个数至少为3个,且为奇数个
哨兵采用"心跳"机制,每隔一秒向master发ping,若有半数以上哨兵没有得到回应,按照少数服从多数原则,认为主机宕机,开始进行容灾处理

哨兵的配置文件sentinel.conf文件
使用一台系统的三个端口模拟3个哨兵
image.png
配置image.png
mymaster是自定义主机名称,然后是主服务器的ip地址和端口号,最后是投票数,投票大于等于该数则启动容灾处理
使master宕机,哨兵会自动从slave中选举出新的master服务器,并把其他slave挂至该服务器。
在原来的master重启后,哨兵将其挂至现有的master上

4.4 安全设置

1)设置密码
访问Redis默认没有密码,可以通过配置redis.conf文件中的requirepass
2)绑定ip
修改redis.conf中的bind ip1 ip2...
注释掉后表示所有ip都可以访问
3)修改默认端口
修改redis.conf中的port xxxx

第五章 Jedis操作Redis

5.1 下载Jedis和Common-Pool
maven导入jar包

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

会自动引入commons-pool2

5.2 使用Jedis
新建一个类,创建Jedis对象,指定连接的redis服务器的ip,端口

 public static void main(String[] args) {
        //创建Jedis对象,指定连接的redis服务器的ip,端口
        /**
         * String host:redis所在的linux服务器的ip
         * int port:redis运行的端口号
         */
        String host = "xxxxx";
        int port = xxxx;
        Jedis jedis = new Jedis(host, port);
        jedis.auth("xxxx");


        //调用jedis对象的方法,操作Redis数据
        String set = jedis.set("break", "豆浆油条");
        String aBreak = jedis.get("break");
        System.out.println("break:" + aBreak);

        //mset一次创建多个key
        String mset = jedis.mset("lunch", "红烧肉", "dinner", "稀饭");
        List<String> mget = jedis.mget("lunch", "break", "dinner", "supper");
        mget.forEach(System.out::println);

    }

使用JedisPool

创建工具类JedisUtil

public class RedisUtil {
    private static JedisPool jedisPool = null;

    //创建JedisPool对象
    public static JedisPool open(String host, int port, String password){
        if (jedisPool == null){
            //创建JedisPool
            //创建jedisPoolConfig,给config设置连接池的参数,使用config对象创建JedisPool
            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            //设置config的参数
            jedisPoolConfig.setMaxTotal(20);//最大的线程数,每个线程就是一个Jedis
            jedisPoolConfig.setMaxIdle(2);//最大空闲数
            jedisPoolConfig.setTestOnBorrow(true);//设置检查项为true,表示从线程池中获取的对象一定是经过检查可用的
            //创建jedispool
            /**
             * jedisPoolConfig:配置JedisPoolConfig
             * host:表示主机ip
             * port:表示端口
             * timeout:表示超时时间
             * password:redis的密码
             *
             */
            jedisPool = new JedisPool(jedisPoolConfig, host,
                    port, 100, password);
        }
        return jedisPool;
    }

    //关闭Pool对象
    public static void close(){
        if (jedisPool != null){
            jedisPool.close();
        }
    }

}

调用工具类获取连接池,从池中获取对象

public class RedisString2 {
    public static void main(String[] args) {
        //创建Jedis对象,指定连接的redis服务器的ip,端口
        /**
         * String host:redis所在的linux服务器的ip
         * int port:redis运行的端口号
         */
        String host = "120.79.69.241";
        int port = 6379;
        JedisPool jedisPool = null;
        Jedis jedis = null;
        try {
            jedisPool = RedisUtil.open(host, port, "123456");
            jedis = jedisPool.getResource();
            //调用jedis对象的方法,操作Redis数据
            String set = jedis.set("break", "豆浆油条");
            String aBreak = jedis.get("break");
            System.out.println("break:" + aBreak);

            //mset一次创建多个key
            String mset = jedis.mset("lunch", "红烧肉", "dinner", "稀饭");
            List<String> mget = jedis.mget("lunch", "break", "dinner", "supper");
            mget.forEach(System.out::println);

        }finally {
            RedisUtil.close();
            if (jedis != null)
                jedis.close();
        }
    }
}