Redis
1、Redis 简介
1.1、Redis 是什么?
Redis 是一个开源的,使用 ANSI C 编写,高性能的 Key-Value 的 NoSQL 数据库。
1.2、Redis 特点
(1)基于内存
(2)可持久化数据
(3)具有丰富的数据结构类型,适应非关系型数据的存储需求
(4)支持绝大多数主流开发语言,如 C、C++、Java、Python、R、JavaScript等。
(5)支持集群模式,高效、稳定。
1.3、数据模型
(1)键值对形式
(2)Redis 的数据结构类型,指的就是 Redis 值的结构类型
1.4、Redis 作用
(1)本质是数据库,能村塾数据
Redis 能灵活处理菲关系型数据的读、写问题,是对 MySQL 等关系型数据库的补充
新浪微博就是使用 Redis 集群做数据库。
(2)缓存数据
所谓缓存,就是将数据加载到内存中后直接使用,而不是每次都通过 IO 流从磁盘上读取。好处:读写效率高
而 Redis 则是将数据直接存储在内存中,只有当内存空间不足时,将部分数据持久化到磁盘上。
2 Redis 安装
2.1、说明
在 Linux 上安装 Redis.
而 Redis 官方只提供了源码,并没有提供经过编译之后的安装包。
因此,安装 Redis,要先编译、后安装。(即源码安装方式)
2.2、Redis 安装步骤
(1)下载,上传到 Linux 服务器,并解压
(2)预编译(实际上是检查编译环境的过程)
进入目录:cd /opt/soft/redis-3.2.9/deps/jemalloc
执行预编译 ./configure
在预编译的过程中,会检测安装 redis 所需的相关依赖,依次安装即可。
(a)缺少 c 编译环境 yum -y install gcc-c++
预编译不是必须的步骤,它只是在检查编译过程中需要的环境是否满足。
通常源码包中,都有一个可执行的 configure 脚本,这个脚本执行预编译的脚本。但是有一些源码包中,没有该文件,可以省略预编译步骤。
(3)编译 cd /opt/soft/redis-3.2.9/src
make
(4)安装 cd /opt/soft/redis-3.2.9/src
make install
(5)启动 redis 服务器(指定配置文件)
拷贝 redis.conf 文件到 /etc 目录下,方便管理
cp /opt/soft/redis-3.2.9/redis.conf /etc/
/usr/local/bin/redis-server /etc/redis.conf(启动 redis 服务器并指定配置文件)
(6)启动 redis 客户端,登录 /usr/local/bin/redis-cli (如果配置文件有指定端口号,则 /usr/local/bin/redis-cli -h 指定的端口号)
(7)安装成功
2.3、redis.conf 常用配置说明
2.3.1、requirepass foobar
给 redis 设置密码
在客户端使用 auth 命令,验证密码
2.3.2、databases 16
redis 默认有 16 个数据库,寻址角标从 0 开始。默认连接 db0
客户端使用 select 命令,切换数据库
2.3.3、port 6379
指定 redis 的服务端口,默认 6379
2.3.4、daemonize no
redis 默认关闭后台进程模式,改成 yes,redis 服务在后台启动
2.3.5、loglevel notice
2.3.6 logfile ""
redis 日志输出目录,默认不输出日志到文件
2.3.7 dbfilename dump.rdb、dir ./
指定数据持久化的文件名及目录
2.4、将 redis 添加为系统服务
2.4.1、第一步:开启后台模式
修改配置文件,将 daemonize 改为 yes
2.4.2、第二步:创建 shell 脚本
说明:Linux 系统服务,在 /etc/init.d 目录下创建 redis 脚本
########################### #chkconfig: 2345 10 90 #description: Start and Stop redis PATH=/usr/local/bin:/sbin:/usr/bin:/bin REDISPORT=6379 EXEC=/usr/local/bin/redis-server REDIS_CLI=/usr/local/bin/redis-cli PIDFILE=/var/run/redis_6379.pid CONF="/etc/redis.conf" PASSWORD=$(cat $CONF|grep '^\s*requirepass'|awk '{print $2}'|sed 's/"//g') case "$1" in start) if [ -f $PIDFILE ] then echo "$PIDFILE exists, process is already running or crashed" else echo "Starting Redis server..." $EXEC $CONF fi if [ "$?"="0" ] then echo "Redis is running..." fi ;; stop) if [ ! -f $PIDFILE ] then echo "$PIDFILE does not exist, process is not running" else PID=$(cat $PIDFILE) echo "Stopping ..." if [ -z $PASSWORD ] then $CLIEXEC -p $REDISPORT shutdown else $CLIEXEC -a $PASSWORD -p $REDISPORT shutdown fi #$REDIS_CLI -p $REDISPORT SHUTDOWN while [ -x ${PIDFILE} ] do echo "Waiting for Redis to shutdown ..." sleep 1 done echo "Redis stopped" fi ;; restart|force-reload) ${0} stop ${0} start ;; *) echo "Usage: /etc/init.d/redis {start|stop|restart|force-reload}" >&2 exit 1 esac ##############################
2.4.3、第三步:添加 shell 脚本可执行权限
[root@node0927 ~]chmod +x /etc/init.d/redis
2.4.4、第四步:添加 redis 开机启动
[root@node0927 ~]chkconfig redis on
3 redis 的键 key
3.1、key 的类型
redis 的 key 值是二进制安全的,这意味着可以用任何二进制序列作为 key 值,从形如 “foo” 的简单字符串到一个 JPEG 文件的内容都可以。
空字符串也是有效 key 值
redis 建议使用字符串作为 key 的类型
3.2、key 取值规范
(1)键值不需要太长,消耗内存,在数据中查找这类键值的计算成本较高
(2)键值不宜过短,可读性较差,通常建议见名知意
3.2.1、取值示例
将如下数据库表中的数据,转换为 redis 的 key-value 存储
id | username | password | |
1 | lisi | 111111 | lisi@163.com |
3.3、key 命令
(1)exists key:检查给定 key 是否存在
(2)del key:删除一个 key
(3)del key1 key2 key3:删除多个 key
(4)keys pattern(模糊查找):查找所有符合给定模式 pattern 的 key.
keys *:匹配数据库中所有 key
keys n?me:匹配 name、neme、nfme等等
keys n*:匹配 name、n、namef等等
keys n[ae]me:只能匹配 name、neme
(5)expire key seconds:指定 key 的过期时间
新添加的 key,如果没有指定过期时间,则会一致保存
可以对一个已经带有生存时间的 key 执行 EXPIRE 命令,新指定的生存时间会取代旧的生存时间
(6)ttl key (time to live):查看某个 key 的剩余过期时间,返回值:
-2 表示这个 key 已经过期,删除掉
-1 表示没有设置过期时间
(7)rename 语法格式:rename key newkey
将 key 改名为 newkey
当 key 和 newkey 相同,或者 key 不存在时,返回一个错误
当 newkey 已经存在时,RENAME 命令将覆盖旧值
(8)type key:查看 key 对应的 value 的数据结构类型
其他 key 命令见 redis 帮助文档 http://doc.redisfans.com/
4 Redis 的值 value(数据结构类型)
Redis 的数据结构类型,指的就是 redis 的值 value 的类型
Redis 常用的数据结构类型:string、list、set、storedSet、hash
4.1、string 类型
string 类型是 redis 最常用的数据结构类型,存储的值为字符串。
4.1.1、string 相关命令
set key value:设置一个 key,值为 value,类型为 string 类型;如果这个 key 已经存在,则更新这个 key 的值。
返回值
1 表示成功
0 表示失败
setnx key value:如果这个 key 不存在,则设置一个 key,值为 value;如果 key 存在,则不做更新。
返回值
1 表示成功
0 表示失败
get key:获取 key 对应的 value 值;如果 key 不存在,则返回 nil
mget key1 key2 key3:一次获取多个 key 的值,如果对应 key 不存在,则对应返回 nil
incr key:将 key 中储存的数字值增一,然后返回。如果这个 key 不存在,那么 key 的值先被初始化为 0,然后再执行 INCR 操作。如果这个 key 对应的 value 值,不能表示数字,则会返回一个错误。
incrby key increment:将 key 增加指定的步长值
decr key:将 key 中存储的数字值减一,然后返回。如果这个 key 不存在,那么 key 的值会先被初始化为 0,然后再执行 DECR 操作。如果这个 key 对应的 value 值,不能表示数字,则会返回一个错误。
Redis 的 key 是单线程模式,这意味一瞬间只有一个线程能够持有这个 key,所以可以使用 redis 解决部分涉及线程安全的业务。
decrby key decrement:将 key 减少对应的步长值
append key value:如果 key 已经存在,则将 value 追加到这个 key 原先的 value 值的末尾。如果这个 key 不存在,则执行 set 操作。
4.1.2、string 类型的应用场景
(1)、做与统计有关的业务,如新浪微博(微信朋友圈)中的点赞功能
(2)解决多线程的线程安全问题。
Redis的key是单线程模式,这就意味一瞬间只有一个线程能够持有这个key,所以可以使用redis解决部分涉及线程安全的业务,比如说抢购、秒杀。
4.2、List 类型
4.2.1、特点
(1)、基于Linked List实现
(2)、元素是字符串类型
(3)、列表头尾增删快,中间增删慢,增删元素是常态
(4)、元素可以重复出现
(5)、最多包含2^32-1元素
列表的索引
从左至右,从0开始
从右至左,从-1开始
5.2.2、List 类型相关命令
lpush key value [value ...]
将一个或多个值value插入到列表key的表头(即从左边插入);
如果有多个value值,那么各个value值按从左到右的顺序依次插入到表头:比如说,对空列表mylist执行命令LPUSH mylist a b c,列表的值将是 c b a 这等同于原子性地执行 LPUSH mylist a 、 LPUSH mylist b 和 LPUSH mylist c 三个命令;
如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。
当 key 存在但不是列表类型时,返回一个错误。
rpush key value [value ...]
尾部添加(从右向左),操作同上。
llen key
返回key对应list的长度,key不存在返回0,如果key对应类型不是list返回错误
lindex key index
index 元素在list列表中的下角标,从0开始;
lindex 是从左到右取元素
lrange key start stop
获取指定区间的所有元素;
下角标从0开始,0表示第一个元素,1表示第二个,依次类推;
-1表示最后一个元素,-2表示倒数第二个元素,依次类推;
lpop key
移除并返回列表中的第一个元素
rpop key
移除并返回列表中的最后一个元素。
4.2.3、List 类型应用场景
(1)处理排名类业务。如新浪微博评论、论坛回帖楼层等。
(2)聊天室
4.3、Hash 类型(散列)
4.3.1、特点
(1)由Field和与之关联的value组成map键值对
(2)field和value是字符串类型;
(3)一个hash中最多包含2^32-1键值对。
4.3.2、Hash 相关命令
hset key field value
设置hash field为指定值,如果key不存在,则先创建
如果field已经存在,那么将更新这个field的值。
hget key field
获取指定的hash field
hmget key filed1....fieldN
获取全部指定的hash filed
hmset key filed1 value1 ... filedN valueN
同时设置hash的多个field
hexists key field
测试指定field是否存在
hdel key field
删除指定的hash field
hlen key
返回指定hash的field数量
hkeys key
返回hash的所有field
hvals key
返回hash的所有value
hgetall
返回hash的所有filed和value
4.3.3、Hash 的用途(能使用 Hash 的时候尽量使用 hash)
节约内存空间:
redis每创建一个键,都会为这个键储存一些附加的管理信息(比如这个键的类型,这个键最后一次被访问的时间等等)
redis的key相对于值来说,更珍贵!!!
所以数据库里面的键越多,redis数据库服务器在储存附加管理信息方面耗费的内存就越多,在获取key对应的value值时cpu的开销也会更多
Hash结构可以将具有关联关系的一组key-value,存储到同一个hash结构中,从而减少key的数量。
5.3.4、hash 不使用场景
需要设置键过期功能的key:
Redis的key的过期功能只能对键操作,而Hash结构不能单独对某一个filed设置过期功能。
说明:在实际开发中,能使用hash的时候,尽量使用hash!!
4.4、Set 类型(集合)
4.4.1、特点
(1)无序的、去重的;
(2)元素是字符串类型;
(3)最多包含2^32-1元素。
4.4.2、Set 相关命令
sadd key member [member ...](无序不重复)
将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
假如 key 不存在,则创建一个只包含 member 元素作成员的集合。
当 key 不是集合类型时,返回一个错误。
smembers key
返回集合 key 中的所有成员。
不存在的 key 被视为空集合。
spop key
移除并返回集合中的一个随机元素。
被移除的随机元素。
当key不存在或key是空集时,返回nil。
scard key
返回集合key的基数(集合中元素的数量)。
集合的基数。
当key不存在时,返回0。
交集、并集、差集sinter sunion sdiff
sinter key [key ...]
返回一个集合的全部成员,该集合是所有给定集合的交集。
不存在的 key 被视为空集。
sunion key [key ...]
返回一个集合的全部成员,该集合是所有给定集合的并集。
不存在的 key 被视为空集。
sdiff key [key ...]
返回一个集合的全部成员,该集合是所有给定集合之间的差集。
不存在的 key 被视为空集。
5.4.3、应用场景
(1)新浪微博的共同关注
需求:当用户访问另一个用户的时候,会显示出两个用户共同关注哪些相同的用户
设计:将每个用户关注的用户放在集合中,求交集即可
实现如下:
peter={'john','jack','may'}
ben={'john','jack','tom'}
那么peter和ben的共同关注为:
SINTER peter ben 结果为{'john','jack'}
4.5 SortedSet 类型
4.5.1 特点
(1)类似Set集合;
(2)有序的、去重的;
(3)元素是字符串类型;
(4)每一个元素都关联着一个浮点数分值(Score),并按照分值从小到大的顺序排列集合中的元素。分值可以相同
(5)最多包含2^32-1元素
4.5.2、适用场景
适用于需要有序且唯一的业务或操作:
(1)网易音乐排行榜
分析:
每首歌的歌名作为元素(唯一、不重复)
每首歌的播放次数作为分值
ZREVRANGE来获取播放次数最多的歌曲(就是最多播放榜了,云音乐热歌榜,没有竞价,没有权重)
5 Jedis 连接 redis 服务器
5.1、项目结构
5.2、Jedis 连接 redis 服务端
1 package cn.mgy.test; 2 3 import java.util.Set; 4 5 import org.junit.Test; 6 7 import redis.clients.jedis.Jedis; 8 9 10 public class TestJedis { 11 12 @SuppressWarnings("resource") 13 @Test 14 public void testJedisConnnect() { 15 try { 16 // 连接 redis 服务器端(使用 host) 17 Jedis jedis = new Jedis("192.168.190.88"); 18 jedis.auth("123456"); 19 System.out.println("连接redis服务器成功!!"); 20 // 测试redis服务器是否正在运行 21 System.out.println("redis服务器正在运行吗?"+jedis.ping()); 22 System.out.println("redis服务器信息?\n"+jedis.info()); 23 jedis.set("jediskey", "apple"); 24 String value = jedis.get("jediskey"); 25 System.out.println(value); 26 Set<String> keys = jedis.keys("*"); 27 for (String string : keys) { 28 System.out.println(string); 29 } 30 } catch (Exception e) { 31 // TODO Auto-generated catch block 32 e.printStackTrace(); 33 } 34 } 35 }