Redis
第 1 节 Redis 介绍
1.1 Redis 简介
Redis 全称为 Remote Dictionary Server,表示远程字典服务器,是跨平台的非关系型数据库。Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API。Redis 通常被称为数据结构服务器,因为值(value)可以是字符串(String)、哈希(Hash)、列表(list)、集合(sets)和有序集合(sorted sets)等类型。
BSD 开源协议是一个给于使用者很大自由的协议。可以自由的使用,修改源代码,也可以将修改后的代码作为开源或者专有软件再发布
Redis 有以下三个特点:
- Redis 支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis 不仅仅支持简单的 key-value 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储。
- Redis 支持数据的备份。
1.2 Redis 优势
性能极高:Redis 读的速度是110000次/s,写的速度是81000次/s 。
丰富的数据类型:Redis 支持二进制案例的 Strings,Lists,Hashes,Sets 及 Sorted Sets 数据类型操作。
原子性:Redis 的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过 MULTI 和 EXEC 指令包起来。
丰富的特性:Redis 还支持 publish/subscribe,发布订阅,消息发送,key 过期等等特性。
1.3 NoSQL 介绍
1.3.1 NoSQL 概念
NoSQL:即非关系型数据库。NoSQL 有时也称作 Not Only SQL 的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。
NoSQL:用于超大规模数据的存储。(例如谷歌或 Facebook 每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。
1.3.2 NoSQL 出现原因
今天我们可以通过第三方平台可以很容易的访问和抓取数据。用户的个人信息,社交网络,地理位置,用户生成的数据和用户操作日志已经成倍的增加。我们如果要对这些用户数据进行挖掘,那 SQL 数据库已经不适合这些应用了, NoSQL 数据库的发展却能很好的处理这些大的数据。
1.4 BASE 理论
BASE:全称:Basically Available(基本可用),Soft state(软状态),和 Eventually consistent(最终一致性)三个短语的缩写,来自 ebay 的架构师提出。是基于CAP定律逐步演化而来。
其核心思想是即使无法做到强一致性,但每个应用都可以根据自身业务特点,才用适当的方式来使系统打到最终一致性。
1.4.1 Basically Available
Basically Available:基本可用。假设系统,出现了不可预知的故障,但还是能用,相比较正常的系统而言:
(1)响应时间上的损失:正常情况下的搜索引擎 0.5 秒即返回给用户结果,而基本可用的搜索引擎可以在 1 秒作用返回结果。
(2)功能上的损失:在一个电商网站上,正常情况下,用户可以顺利完成每一笔订单,但是到了大促期间,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面。
1.4.2 Soft state
Soft state:软状态。相对于原子性而言,要求多个节点的数据副本都是一致的,这是一种 “硬状态”。
软状态指的是:允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。
1.4.3 Eventually consistent
Eventually consistent:最终一致性。上面说软状态,但不可能一直是软状态,必须有个时间期限。在期限过后,应当保证所有副本保持数据一致性。从而达到数据的最终一致性。这个时间期限取决于网络延时,系统负载,数据复制方案设计等等因素。
即系统能够保证在没有其他新的更新操作的情况下,数据最终一定能够达到一致的状态,因此所有客户端对系统的数据访问最终都能够获取到最新的值。
1.4.4 最终一致性常用分类
1、因果一致性(Causal consistency)
即如果节点 A 在更新完某个数据后通知了节点 B,那么节点 B 之后对该数据的访问和修改都是基于 A 更新后的值。于此同时,和节点 A 无因果关系的节点 C 的数据访问则没有这样的限制。
2、读己之所写(Read your writes)
即节点 A 更新一个数据后,它自身总是能访问到自身更新过的最新值,而不会看到旧值。其实也算一种因果一致性。
3、会话一致性(Session consistency)
会话一致性将对系统数据的访问过程框定在了一个会话当中,系统能保证在同一个有效的会话中实现 “读己之所写” 的一致性,也就是说,执行更新操作之后,客户端能够在同一个会话中始终读取到该数据项的最新值。
4、单调读一致性(Monotonic read consistency)
单调读一致性是指如果一个节点从系统中读取出一个数据项的某个值后,那么系统对于该节点后续的任何数据访问都不应该返回更旧的值。
5. 单调写一致性(Monotonic write consistency)
指一个系统要能够保证来自同一个节点的写操作被顺序的执行。
6、总结
然而,在实际的实践中,这 5 种系统往往会结合使用,以构建一个具有最终一致性的分布式系统。实际上,不只是分布式系统使用最终一致性,关系型数据库在某个功能上,也是使用最终一致性的,比如备份,数据库的复制过程是需要时间的,这个复制过程中,业务读取到的值就是旧的。当然,最终还是达成了数据一致性。这也算是一个最终一致性的经典案例。
BASE 理论面向的是大型高可用可扩展的分布式系统,和传统事务的 ACID 是相反的,它完全不同于 ACID 的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间是不一致的。
第 2 节 安装 Redis
2.1 Windows 安装
由于 Redis 官方不推荐 Windows 安装 Redis,因此 Windows 系统只能安装微软维护的免费的 Redis。
Redis 也有图形化界面,但推荐使用 Linux。
第 3 节 Redis 命令
3.1 通用命令
Redis 存储数据采用的是 key-value 进行存储,不管 value 是什么类型,针对的 key 操作都属于通用操作。
del key # 删除键
exists key # 检测键是否存在,1-表示存在,0-表示不存在
expire key seconds # 为键设置过期时间 单位是秒
pexpire key milliSeconds # 为键设置过期时间 单位是毫秒
keys pattern # 使用正则表达式查找键
persist key # 持久化键,过期时间就相当于没有了
ttl key # 获取键的剩余过期时间 单位是秒
pttl key # 获取键的剩余过期时间 单位是毫秒
type key # 获取键的存储的值的类型
select 0 ~ 15 # 选择操作的库
move key db # 移动键到另外一个库中
flushdb # 清空当前所在的数据库
flushall # 清空全部数据库
dbsize # 查看当前数据库中有多少个键
lastsave # 查看最后一次操作的时间
monitor # 实时监控Redis服务接收到的命令
Java 中操作这些命令是一样的,只是能添加不同的参数。
3.2 String 命令
set key value # 设置键的值,如果存在就是修改,不存在就是增加
get key # 获取键的值
mset key1 value1 key2 value2 ... # 批量设置键的值
mget key1 key2 ... # 批量获取键的值
setex key seconds value # 设置键的值,同时设置键的过期时间
setnx key value # 当键不存在时才设置键的值
incr key # 将键存储的值增加1,只有存储数字的时候有效
incr key increment # 将键存储的值增加给定的增量,只有存储数字的时候有效
decr key # 将键存储的值减去1,只有存储数字的时候有效
decr key decrement # 将键存储的值减少给定减量,只有存储数字的时候有效
append key value # 当键存在且存储的值是一个字符串时,将值追加到存储的字符串的末尾
3.3 Hash 命令
hset key field value # 设置键存储的字段和值
hget key field # 获取键存储的字段值
hmset key field value[field value ...] # 批量设置键的存储的字段和值
hmget key [field ...] # 批量获取键存储的字段值
hincrby key field increment # 键存储的字段值自增1
hsetnx key field value # 不存在字段就添加
hexists key field # 检查键存储的字段是否存在
hdel key field [field ...] # 批量删除键中存储的字段
hgetall key # 获取当前键存储的字段和值
hkeys key # 获取当前键存储的所有字段
hvals key # 获取当前键存储的所有值
hlen key # 获取当前键存储的字段数量
3.4 List 命令
# 存储数据(从左侧插入数据,从右侧插入数据)
lpush key value [value ...]
rpush key value [value ...]
lpushx key value # 将一个值插入到已存在的列表头部
rpushx key value # 为已存在的列表添加值
lset key index value # 通过索引设置列表元素的值
# 弹栈方式获取数据(左侧弹出数据,从右侧弹出数据)
lpop key
rpop key
lrange key start stop # 获取列表指定范围内的元素 -1表示末尾
lindex key index # 获取指定索引位置的数据
llen key # 获取列表的长度
# 删除列表中的数据(他是删除当前列表中的count个value值,count > 0从左侧向右侧删除,count < 0从右侧向左侧删除,count == 0删除列表中全部的value)
lrem key count value
# 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
ltrim key start stop
# 将一个列表中最后的一个数据,插入到另外一个列表的头部位置
rpoplpush list1 list2
3.5 Set 命令
# 存储数据
sadd key member [member ...]
# 获取数据(获取全部数据)
smembers key
# 随机获取一个数据(获取的同时,移除数据,count默认为1,代表弹出数据的数量)
spop key [count]
# 交集(取多个set集合交集)
sinter set1 set2 ...
# 并集(获取全部集合中的数据)
sunion set1 set2 ...
# 差集(获取多个集合中不一样的数据)
sdiff set1 set2 ...
# 删除数据
srem key member [member ...]
# 查看当前的set集合中是否包含这个值
sismember key member
3.6 Zset 命令
# 添加数据(score必须是数值。member不允许重复的。)
zadd key score member [score member ...]
# 修改member的分数(如果member是存在于key中的,正常增加分数,如果memeber不存在,这个命令就相当于zadd)
zincrby key increment member
# 查看指定的member的分数
zscore key member
# 获取zset中数据的数量
zcard key
# 根据score的范围查询member数量
zcount key min max
# 删除zset中的成员
zrem key member [member...]
# 根据分数从小到大排序,获取指定范围内的数据(withscores如果添加这个参数,那么会返回member对应的分数)
zrange key start stop [withscores]
# 根据分数从大到小排序,获取指定范围内的数据(withscores如果添加这个参数,那么会返回member对应的分数)
zrevrange key start stop [withscores]
# 根据分数的返回去获取member(withscores代表同时返回score,添加limit,就和MySQL中一样,如果不希望等于min或者max的值被查询出来可以采用 ‘(分数’ 相当于 < 但是不等于的方式,最大值和最小值使用+inf和-inf来标识)
zrangebyscore key min max [withscores] [limit offset count]
# 根据分数的返回去获取member(withscores代表同时返回score,添加limit,就和MySQL中一样)
zrangebyscore key max min [withscores] [limit offset count]
第 4 节 Java 连接 Redis
导入依赖:
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
注意:版本不要过高,过高的版本有些方法被删除了。
测试:
package com.luochen;
import org.junit.Test;
import redis.clients.jedis.Jedis;
public class RedisTest {
@Test
public void test01(){
// 创建Jedis
Jedis jedis = new Jedis("127.0.0.1", 6379);
// 创建key
jedis.set("name","admin");
// 关闭
jedis.close();
}
}