Redis
一、什么是redis
Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库。它通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止Redis支持的键值数据类型如下:
1、字符串类型
2、散列类型
3、列表类型
4、集合类型
5、有序集合类型。
二、redis应用场景
缓存
分布式集群架构中的session分离
聊天室的在线好友列表
任务队列。(秒杀、抢购、12306等等)
应用排行榜
网站访问统计
数据过期处理(可以精确到毫秒)
三、redis与memcache的优缺点
1 、Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
2 、Redis不仅仅支持简单的string类型的数据,同时还提供list,set,hash等数据结构的存储。
3 、Redis支持数据的备份,即master-slave模式的数据备份。
4、内存超出时redis将不常用缓存swap到 磁盘。
5、redis支持集群,添加节点删除节点不丢数据
6、redis是单线程
四、服务端常用命令
Ping 检查连接是否存活 例:ping,返回pong,则存活
Echo 在命令行打印内容 例:echo 文本
Info 获取服务器信息和统计 例:info
Quit 退出客户端 例:quit
Select 选择数据库 例:select 数据库(1-15)
Dbsize 返回当前数据库key的数目 例:dbsize
Flushdb 删除当前数据库中所有的key 例:flushdb
Flushall 删除所有数据库中所有的key 例:flushall
五、string类型常用命令
在redis中字符串类型的value最多可以容纳的数据长度512M
Set 赋值 例:set 键 值
Get 获取值 例:get 键
Append 追加字符串 例:append 键
Incr 自增(+1) 例:incr 键
Decr 自减(-1) 例:decr 键
Incrby 自增,增加指定步长 例:incrby 键 步长
Decrby 自减,减少指定步长 例:decrbydecr 键 步长
Getset 先获取元素在赋值 例:getset 键 值
Setex 赋值并指定key的存活时间 例:setex 键 存活秒数 值
Setnx key不存在就赋值 例:setnx 键 值
Strlen 返回key的值得长度 例:strlen 键
Setrange 字符串替换(包含起始位置) 例:setrange 键 开始位置 替换的值
Getrange 获取指定位置字符串 例:getrange 键 开始位置 结束位置
Mset 同时设置多个key的值 例:mget key[key2...]
六、Hash(散列类型)常用命令
还是叫散列类型,它提供了字段和字段值的映射。字段值只能是字符串类型,不支持散列类型、集合类型等其它类型。
Hset 给key中的某个字段赋值 例:hset 键 字段 值
Hget 获取key中的某个字段的值 例:hget 键 字段
Hexists 判断key中是否存在某个字段 例:hexists 键 字段
Hlen 获取key中字段的数量 例:hlen 键
Hdel 删除key中的字段 例:hdel 键 字段[字段2...]
Hgetall 获取key中的所有字段和值 例:hgetall 键
Hmset 同时设置多个字段和值 例:hmset 键 字段 值[字段2]
Hmget 同时获取多个值 例:hmget 键 字段 [字段2]
七、list类型
列表类型(list)可以储存一个有序的字符串列表,常用的操作是向列表两端添加元素,或者获得列表的某一个片段。
Lpush 在list头部添加值 例:lpush 键 值[值2...]
Rpush 在list尾部添加值 例:rpush 键 值[值2...]
Lrange 获取指定位置的数据 例:lrange 值 开始位置 结束位置
Lpop 从头部弹出key的值 例:lpop 键
Rpop 从尾部弹出key的值 例:rpop 键
Llen 返回key的值 例:llen 键
Lset 按下标赋值 例:lset 键 下标 值
Lindex 返回下标的值 例:lindex 键 下标
Ltrim 截取list指定位置的值 例:ltrim 键 开始位置 结束位置
八、set类型
Set就是集合类型,集合中每个元素都不相同,切没有顺序
Sadd 添加值 例:sadd 键 member[member2]
Smembers 遍历集合 例:smembers 键
Scard 获取key的成员数量 例:scard 键
Screm 删除指定成员 例:scem 键 成员[成员2...]
Sisemember 判断成员是否存在 例:sismember 键 成员
Spop 随机弹出一个值(删除) 例:spop 成员
九、sorted set类型
1、在集合类型的基础上有序集合类型为集合中的每个元素都关联一个分数,这使得我们不仅可以完成插入、删除和判断元素是否存在在集合中,还能够获得分数最高或最低的前N个元素、获取指定分数范围内的元素等与分数有关的操作。
2有序集合和list类型二者有着很大区别:
1)列表类型是通过链表实现的,获取靠近两端的数据速度极快,而当元素增多后, 访问中间数据的速度会变慢。
2)有序集合类型使用散列表实现,所有即使读取位于中间部分的数据也很快。
3)列表中不能简单的调整某个元素的位置,但是有序集合可以
4)有序集合要比列表类型更耗内存
Zadd 添加成员 例:zadd 键 分数(score) 成员[...]
Zcard 获取成员数量 例:zcard 键
Zcount 获取指定分数之间的成员数量 例:zcount 键 最小分数 最大分数
Zincrby 给指定成员添加分数 例:zincrby 键 分数 成员
Zrang 遍历指定下标之间的成员[withscores] 例:zrange 键 开始 结束
Zrangebyscore遍历指定分数之间的成员[withscores] 例: zrangebyscore 键 开始 结束 zrank 返回指定成员的下标 例:zrank 键 成员
Zrem 删除指定成员 例:zrem 键 成员[成员2]
Zscore 获取指定成员的分数 例:zscore 键 成员
十、key命令
Keys [*] 获取键,*代表所有 例:keys 键名
Del 删除指定的键 例:del 键[键2...]
Exists 判断键是否存在 例:exists 键
Move 移动一个键到另一个库中 例:exists 键 数据库名
Rename 给键重新命名 例:rename 键 新键名
Renamenx 给键重新命名,当新键存在时不操作 例:renamenx 键 新键
Persist 将键持久化 例:persist 键
Exprie 设置键的存活时间 例:expire 键 秒
Ttl 查看键的剩余存活时间 例:ttl 键
Pttl 查看键的剩余存活时间 例:pttl 键
Randomkey 随机返回一个键 例:randomkey
Type 返回key中的value的类型 例:type键
Save 持久化所有数据库数据 例:save
十一、redis的持久化
Redis的高性能是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中同步到硬盘中,这一过程就是持久化。
Redis支持两种方式的持久化,一种是RDB方式,一种是AOF方式。可以单独使用其中一种或将二者结合使用
1.RDB
RDB方式的持久化是通过快照(snapshotting)完成的,当符合一定条件时Redis会自动将内存中的数据进行快照并持久化到硬盘。
RDB是Redis默认采用的持久化方式,在redis.conf配置文件中默认有此下配置:
save 900 1 (900秒内执行了1次,就存储)
save 300 10 (300秒内存储了10次,就存储)
save 60 10000 (60秒内存储了10000,就存储)
2.AOF
以日志形式记录服务器每一个操作,在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。
默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启:
appendonly yes
十二、RDB持久化方式优劣势:
优势:
1、RDB 是一个非常紧凑(compact)的文件,它保存了Redis 在某个时间点上的数据集。这种文件非常适合用于进行备份:可以自己设置保存频率。
2、RDB 非常适用于灾难恢复(disaster recovery):它只有一个文件,并且内容都非常紧凑,可以(在加密后)将它传送到别的数据中心。
3、 RDB 可以最大化Redis 的性能:父进程在保存RDB 文件时唯一要做的就是fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘I/O 操作。
4、 RDB 在恢复大数据集时的速度比AOF 的恢复速度要快。
劣势:rdb是以每隔一段时间进行一次快照进行的数据持久,如果一旦在这一时间段出现服务器故障,将会灾难性的
十二、AOF持久化方式优劣势:
优势:
1、使用AOF 持久化会让Redis 变得非常耐久(much more durable):你可以设置不同的fsync 策略,比如无fsync ,每秒钟一次fsync ,或者每次执行写入命令时fsync 。
2、Redis 可以在AOF 文件体积变得过大时,自动地在后台对AOF 进行重写
3、AOF 文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Redis 协议的格式保存,因此AOF 文件的内容非常容易被人读懂,对文件进行分析(parse)也很轻松。
劣势:
1、对于相同数量的数据集而言,AOF文件通常要大于RDB文件
2、根据所使用的fsync 策略,AOF 的速度可能会慢于RDB 。
十三、发布与订阅
1.PSUBSCRIBE
PSUBSCRIBE pattern [pattern ...]订阅一个或多个符合给定模式的频道。
每个模式以* 作为匹配符,比如it* 匹配所有以it 开头的频道( it.news 、it.blog 、it.tweets 等等),
news.* 匹配所有以news. 开头的频道( news.it 、news.global.today 等等),诸如此类。
2.SUBSCRIBE
SUBSCRIBE channel [[channel ... ]
订阅给定的一个或多个频道的信息
3.PUBLISH
PUBLISH channel message
将信息message 发送到指定的频道channel 。
4.PUNSUBSCRIBE
PUNSUBSCRIBE [pattern [pattern ...]]
指示客户端退订所有给定模式。
如果没有模式被指定,也即是,一个无参数的PUNSUBSCRIBE 调用被执行,那么客户端使用PSUBSCRIBE命令订阅的所有模式都会被退订。在这种情况下,命令会返回一个信息,告知客户端所有被退订的模式
5.PUBLISH
PUNSUBSCRIBE [pattern [pattern ...]]
指示客户端退订所有给定模式。
如果没有模式被指定,也即是,一个无参数的PUNSUBSCRIBE 调用被执行,那么客户端使用PSUBSCRIBE命令订阅的所有模式都会被退订。在这种情况下,命令会返回一个信息,告知客户端所有被退订的模式
十四、redis与java的链接
Redis与java的链接有好几种,有兴趣可以百度,这里使用jredis链接
需求:jedis jar包
代码:Jedis jedis = new Jedis();
Jar包中的方法统一格式jedis.命令();
利用发布订阅+多线程实现聊天小程序源码:
//1.客户端(也是服务端)
package day0907;
import java.util.Scanner;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
public class Ps1 {
private static Jedis jedis = new Jedis();
public final static String PD_A = "pd_a";// 定义频道
@SuppressWarnings("resource")
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Sub sub = new Sub();
sub.start();
while (true) {
System.out.println("请输入内容:");
String s = sc.next();
jedis.publish(PD_A, s);// 发送内容
}
}
}
class Sub extends Thread {
private static Jedis jedis = new Jedis();
@Override
public void run() {
while (true) {
jedis.subscribe(new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
System.out.println("收到信息: " + message);
super.onMessage(channel, message);
}
}, Ps2.PD_B);// 接受消息
}
}
}
//2.服务端(也是客户端)
package day0907;
import java.util.Scanner;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
public class Ps2 {
private static Jedis jedis = new Jedis();
public final static String PD_B="pd_b";//定义频道
@SuppressWarnings("resource")
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Sub2 sub2 = new Sub2();
sub2.start();
while (true) {
System.out.println("请输入内容:");
String s = sc.next();
jedis.publish(PD_B, s);// 发送内容
}
}
}
class Sub2 extends Thread {
private static Jedis jedis = new Jedis();
@Override
public void run() {
while (true) {
jedis.subscribe(new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
System.out.println("收到信息: " + message);
super.onMessage(channel, message);
}
}, Ps1.PD_A);// 接受消息
}
}
}