极速上手内存数据库Redis-1
快速了解Redis
什么是Redis
1 | Redis是一种面向 “Key-Value” 数据类型的内存数据库,可以满足我们对海量数据的快速读写需求 |
Redis的特点
1 | 接下来看一下Redis的一些特点 |
1 | 注意:Redis是一个 单线程 的服务,作者之所以这么设计,主要是为了保证redis的快速,高效,如果涉及了多线程,就需要使用锁机制来解决并发问题,这样执行效率反而会打折扣。 |
Redis的应用场景
1 | 主要应用在高并发和实时请求的场景,例如:新浪微博 |
使用Redis存储数据
Redis安装部署
1 | 下面来看一下redis的安装部署,首先下载redis |
1 | 只要不报错就说明编译安装成功。 |
1 | 3:修改redis.conf配置文件 |
1 | 4:启动redis |
1 | 7:停止redis数据库 |
Redis基础命令
1 | 下面我们来看一下Redis中的基础命令 |
获得符合规则的键:keys
1 | keys 后面可以指定正则表达式 |
scan
1 | 注意:在生产环境下建议禁用keys命令,因为这个命令会查询过滤redis中的所有数据,可能会造成服务阻塞,影响redis执行效率。 |
1 | 向redis中初始化一批数据 |
1 | 使用scan迭代数据,后面游标参数指定为0,表示从头开始迭代key |
1 | SCAN 命令的返回值是一个包含两个元素的数组, |
1 | scan命令此时返回的游标为3 |
1 | 这一次使用scan命令,返回的游标为0,表示迭代已经结束,整个redis中的key都被迭代完了。 |
1 | 所以,如果redis中有很多key,我们可以使用scan命令来迭代,一次迭代一部分,不至于造成阻塞,如果redis中的key比较少,那么使用keys * 也是可以的。 |
1 | 此时实际返回的key的数量是4个,但是游标还是3,相当于还是迭代了10条数据,只不过不满足条件的没有返回而已。 |
判断键是否存在:exists
1 | 127.0.0.1:6379> exists a |
删除键:del
1 | 127.0.0.1:6379> del a |
1 | 注意:del也支持一次删除多个key |
获得键值的类型:type
1 | 返回值可能是这五种类型(string,hash,list,set,zset) |
帮助命令:help
1 | 127.0.0.1:6379> help set |
退出客户端:quit/exit
1 | 127.0.0.1:6379> quit |
1 | 不过我还是习惯使用ctrl+c退出redis-cli客户端 |
Redis多数据库特性
1 | Redis默认支持16个数据库,通过databases参数控制的 |
select
1 | 每个数据库对外都是以一个从0开始的递增数字命名,不支持自定义 |
1 | 一般在工作中会使用2~3个数据库,可以根据业务类型来分库,不同业务的数据存到不同的库里面 |
1 | 并且我们在redis中使用多个库,并不能提高redis的存储能力,因为默认这16个库共用redis的内存存储空间,如果想要提高redis的存储能力,需要给我们的服务器增加内存才可以。 |
flushall
1 | 127.0.0.1:6379[15]> set x 1 |
flushdb
1 | 如果只想清空当前数据库中的数据,可以使用flushdb |
2 Redis核心实践
1 | 下面来看一下redis中的常用数据类型 |
Redis数据类型之string
1 | 字符串类型是redis中最基本的数据类型,它能存储任何形式的内容,包含二进制数据,甚至是一张图片 |

添加数据 set
1 | 127.0.0.1:6379> set str a |
查询数据 get
1 | 127.0.0.1:6379> get str |
一次添加多条数据
1 | 127.0.0.1:6379> mset str1 a1 str2 a2 |
一次查询多条数据
1 | 127.0.0.1:6379> mget str1 str2 |
递增1
1 | 1属于特殊的字符串 |
1 | 127.0.0.1:6379> set num 1 |
递减1
1 | 127.0.0.1:6379> decr num |
递增指定数值(整数类型)
1 | 127.0.0.1:6379> incrby num 2 |
递减指定数值(整数类型)
1 | 127.0.0.1:6379> decrby num 2 |
递增指定数值(float类型)
1 | 127.0.0.1:6379> incrbyfloat num 2.1 |
获取指定key的value长度
1 | 127.0.0.1:6379> get str |
Redis数据类型之hash
1 | hash类型的值存储了字段和字段值的映射(就是hash里还包含key-value),字段和字段值只能是字符串,不支持其他数据类型 |
1 | 命令 格式 解释 |
添加数据 hset
1 | 127.0.0.1:6379> hset user:1 name zs // user:1看成key,这里只是为了方便识别是哪一个用户,不一定要是这种样子;name zs看成value,value里包含了key value |
查询数据 hget
1 | 127.0.0.1:6379> hget user:1 name |
向一个hash中同时添加多个k-v hmset
1 | 127.0.0.1:6379> hmset user:2 name lisi age 18 |
查询一个hash数据中多个k的值 hmget
1 | 127.0.0.1:6379> hmget user:2 name age |
查询一个hash数据中的所有k-v hgetall
1 | 127.0.0.1:6379> hgetall user:2 |
判断一个hash数据中是否存在指定k hexists
1 | 127.0.0.1:6379> hexists user:2 name |
对一个hash数据中指定k的v进行递增 hincrby
1 | 127.0.0.1:6379> hincrby user:2 age 1 |
删除一个hash数据中的指定k hdel
1 | 127.0.0.1:6379> hset user:2 city beijing |
获取一个hash数据中的所有k hkeys
1 | 127.0.0.1:6379> hkeys user:2 |
获取一个hash数据中的所有v hvals
1 | 127.0.0.1:6379> hvals user:2 |
获取一个hash数据中有多少个k hlen
1 | 127.0.0.1:6379> hlen user:2 |
Redis数据类型之list
1 | list是一个有序的字符串列表,列表内部是使用双向链表(linked list)实现的 |
1 | 命令 格式 解释 |
添加元素(左侧添加) lpush
1 | 127.0.0.1:6379> lpush list1 a // list1相当于key |
取出元素(左侧取元素) lpop
1 | 127.0.0.1:6379> lpop list1 |
添加元素(右侧添加) rpush
1 | 127.0.0.1:6379> rpush list2 x |
取出元素(右侧取元素) rpop
1 | 127.0.0.1:6379> rpop list2 |
列表长度 llen
1 | 127.0.0.1:6379> lpush list3 a b c d |
获取列表中的元素 lrange
1 | 127.0.0.1:6379> lrange list3 0 -1 |
查询指定角标元素 lindex
1 | 127.0.0.1:6379> lindex list3 1 |
修改指定角标元素 lset
1 | 127.0.0.1:6379> lset list3 1 m |
Redis数据类型之set
1 | set是一个集合 |
1 | 命令 格式 解释 |
向集合中添加元素 sadd
1 | 127.0.0.1:6379> sadd set1 a |
获取集合中所有元素 smembers
1 | 127.0.0.1:6379> smembers set1 |
删除集合中的元素 srem
1 | 127.0.0.1:6379> srem set1 a |
判断元素是否存在集合中 sismember
1 | 127.0.0.1:6379> sismember set1 b |
两个集合取差集 sdiff
1 | 127.0.0.1:6379> sadd set2 a b c |
两个集合取交集 sinter
1 | 127.0.0.1:6379> sinter set2 set3 (intersect) |
两个集合取并集 sunion
1 | 127.0.0.1:6379> sunion set2 set3 |
获取集合长度(获取集合中元素的个数) scard
1 | 127.0.0.1:6379> scard set3 |
Redis数据类型之sorted set
1 | 有序集合,在集合类型的基础上为集合中的每个元素都关联了一个分数,根据分数进行排序,这样就实现了有序。 |
1 | 命令 格式 解释 |
向集合中添加元素 zadd
1 | 127.0.0.1:6379> zadd zset1 5 a |
查询集合中指定元素的分值 zscore
1 | 127.0.0.1:6379> zscore zset1 a |
根据角标获取集合中的元素(按照正序) zrange
1 | 127.0.0.1:6379> zrange zset1 0 -1 |
根据角标获取集合中的元素(按照倒序) zrevrange
1 | 127.0.0.1:6379> zrevrange zset1 0 -1 |
对集合中元素的分值进行递增 zincrby
1 | 127.0.0.1:6379> zincrby zset1 3 a |
获取集合中元素的个数 zcard
1 | 127.0.0.1:6379> zcard zset1 |
删除集合中的元素 zrem
1 | 127.0.0.1:6379> zrem zset1 a |
1 | 注意: |

1 | 注意:使用set命令时要注意,假如某个key已经存储了其它非string类型,使用set命令赋值后会变成string类型。工作中一定要注意 |
案例:存储高一班的学员信息
1 | 需求:将学员的姓名、年龄、性别、住址信息保存到Redis中 |
1 | 127.0.0.1:6379> hmset stu:1 name xiaoming age 18 sex 0 address beijing |
3 Redis封装工具类技巧
1 | 在这我们以java代码为例,演示一下如何使用java代码操作redis |
1 | <dependency> |
1 | 注意:jedis的版本号和redis的版本号不是一一对应的。 |
单连接方式
1 | 接下来使用单连接的方式操作redis |
1 | package com.imooc.redis; |
1 | 代码执行效果如下: |
1 | 其实在这你会发现,我们前面讲的那些在redis-cli中使用的命令,和jedis中提供的函数名称是一一对应的。切换到代码中来使用也是可以直接上手的。 |
连接池方式
1 | 接下来使用连接池的方式操作redis |
1 | package com.imooc.redis; |
1 | 执行结果: |
案例:提取RedisUtils工具类
1 | 基于redis连接池的方式提取RedisUtils工具类 |
1 | package com.imooc.redis; |
1 | 使用工具类代码 |
1 | package com.imooc.redis; |
4 Redis高级特性
expire 生存时间
1 | Redis中可以使用expire命令设置一个键的生存时间,到时间后Redis会自动删除它 |
1 | expire支持以下操作 |
设置key的过期时间
1 | 127.0.0.1:6379> set abc 123 |
获取key的剩余有效时间
1 | 127.0.0.1:6379> ttl abc |
取消key的过期时间
1 | 127.0.0.1:6379> persist abc |
1 | 此时再查看这个key的剩余有效时间,返回的值是-1,-1表示这个key是一个永久存在的key |
1 | 127.0.0.1:6379> ttl abc |
还可以通过expireat指定key在指定时间点过期
1 | 先获取当前时间戳 |
1 | 过一会再查看这个key的剩余有效时间,返回的是-2,表示这个key被删除了,不存在了 |
1 | 总结一下: |
pipeline 管道
1 | 针对批量操作数据或者批量初始化数据的时候使用,效率高 |

1 | 不使用管道的时候,我们每执行一条命令都需要和redis服务器交互一次 |
1 | 接下来看一个案例 |
1 | package com.imooc.redis; |
1 | 结果如下: |
1 | 在代码执行的过程中,我们可以使用info命令观察数据库中的数据条数 |
1 | 从这可以看出来,针对海量数据的初始化,管道可以显著提高初始化性能。 |
info命令
1 | 在redis-cli中使用>info |
1 | 这里面参数比较多 |
Redis的持久化
1 | Redis持久化简单理解就是把内存中的数据持久化到磁盘中 可以保证Reids重启之后还能恢复之前的数据 |
Redis持久化之RDB
1 | RDB持久化是通过快照完成的,当符合一定条件时Redis会自动将内存中的所有数据执行快照操作并存储到硬盘上,默认存储在dump.rdb文件中 |
1 | Redis什么时候会执行快照? |
1 | RDB的优点:由于存储的有数据快照文件,恢复数据很方便 |

1 | redis重启的时候就会根据dump.rdb进行恢复数据,所以可以将这个本地文件拷贝到其它位置或者节点进行备份。 |
Redis持久化之AOF
1 | AOF持久化是通过日志文件的方式,默认情况下没有开启,可以通过appendonly参数开启 |

1 | 但是RDB持久化的数据还在,但重启后info发现数据库里数据没了。这是因为同时开启两种持久化,默认选择AOF,此时生成的appendonly.aof还是空的,读不到之前的数据 |

1 | 可以用>config set appendonly yes |
1 | 注意:dir参数的值为. 表示当前目录,也就是说我们在哪个目录下启动redis,rdb快照文件和aof日志文件就产生在哪个目录下。 |

1 | # appendfsync always |
1 | 默认是每秒钟执行一次同步操作。appendfsync everysec |
Redis的安全策略
设置数据库密码
1 | 默认情况下访问redis只要网络能通就可以直接访问,这样其实是有一些不安全的,不过我们一般会限制只能在内网访问,这样其实问题也不大。 |
1 | 重启redis服务 |
1 | 注意:在实际工作中一般不会设置密码,因为我们在这设置的密码是明文的,其实意义也不大,针对别有用心的人,你这样设置是没有意义的。 |
bind参数的应用
1 | 在实际工作中,我们的服务器至少会有3个ip地址 |
命令重命名
1 | 咱们前面讲过一个命令是flushall,这个命令是很危险的,它可以把redis中的所有数据全部清空 |
1 | 这样修改之后,就把flushall命令给禁用掉了 |
一个Redis实例最多能存放多少key?
1 | 一个Redis实例最多能存放多少key? |
Redis监控命令-monitor
1 | 这个monitor命令是一把双刃剑。 |
1 | 但是在某些特殊的场景下面它是很有用的 |
5 Redis核心复盘
Redis架构演进
1 | 现在我们使用的Redis是单机的,单机的Redis存在单点故障的问题, |
主从复制
1 | Redis的复制功能支持多个数据库之间的数据同步 |

1 | 这个就是redis的主从复制架构 |
Sentinel
1 | 这个sentinel哨兵机制提供了三个功能 |

1 | 上面这两个sentine1和sentinel2就是使用redis启动的哨兵服务。 |
1 | 这就是Redis中的sentinel哨兵机制。 |
集群
1 | Redis集群是一个无中心的分布式Redis存储架构,可以在多个节点之间数据共享,解决了Redis高可用、可扩展等问题 |
1 | 里面红色的表示是5个master节点,此时redis集群的存储能力就是这5个master节点内存的总和。 |