Redis
文章目录
NoSQL——非关系型数据库
NoSQL,泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在处理web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,出现了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,特别是大数据应用难题。
键值(Key-Value)存储数据库
这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特定的数据。Key/value模型对于IT系统来说的优势在于简单、易部署。但是如果数据库管理员(DBA)只对部分值进行查询或更新的时候,Key/value就显得效率低下了。
举例如:Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB。
列存储数据库
这部分数据库通常是用来应对分布式存储的海量数据。键仍然存在,但是它们的特点是指向了多个列。这些列是由列家族来安排的。
如:Cassandra, HBase, Riak.
文档型数据库
文档型数据库的灵感是来自于Lotus Notes办公软件的,而且它同第一种键值存储相类似。该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如JSON。文档型数据库可以看作是键值数据库的升级版,允许之间嵌套键值,在处理网页等复杂数据时,文档型数据库比传统键值数据库的查询效率更高。
如:CouchDB, MongoDb. 国内也有文档型数据库SequoiaDB,已经开源。
图形(Graph)数据库
图形结构的数据库同其他行列以及刚性结构的SQL数据库不同,它是使用灵活的图形模型,并且能够扩展到多个服务器上。NoSQL数据库没有标准的查询语言(SQL),因此进行数据库查询需要制定数据模型。许多NoSQL数据库都有REST式的数据接口或者查询API。如:Neo4J, InfoGrid, Infinite Graph。
Redis简介
REmote DIctionary Server远程字典服务器(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统,是跨平台的非关系型数据库。
Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API。
Redis 通常被称为数据结构服务器,因为值(value)可以是字符串(String)、哈希(Hash)、列表(list)、集合(sets)和有序集合(sorted sets)等类型。
安装下载
官网:https://redis.io/
中文官网:https://www.redis.net.cn/
Window 下安装
**下载地址:**https://github.com/dmajkic/redis/downloads
Linux 下安装
**下载地址:**http://www.redis.net.cn/download/,下载最新文档版本。
或者Github:https://github.com/redis/redis/releases/tag/6.2.3
![image-20210519134540242](Redis.assets/image-20210519134540242.png)
双击:redis-server.exe
运行服务器
![image-20210519134608119](https://gitee.com/qhzeng/markdown/raw/master/image/image-20210519134608119.png)
![image-20210519134710375](https://gitee.com/qhzeng/markdown/raw/master/image/image-20210519134710375.png)
Redis 数据类型
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
Redis本身就是要用键值对来存储,其中key都是字符串,value有5种数据结构
String(字符串)
一个key对应一个value。
string类型是Redis最基本的数据类型,一个键最大能存储512MB。
string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。
实例
redis 127.0.0.1:6379> SET w3ckey redis
OK
redis 127.0.0.1:6379> GET w3ckey
"redis"
1 SET key value 设置指定 key 的值
2 GET key 获取指定 key 的值。
常用的命令:https://www.redis.net.cn/tutorial/3508.html
Hash(哈希)
Redis hash 是一个键值对集合。
Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。
Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)。
实例
redis 127.0.0.1:6379> HMSET w3ckey name "redis tutorial" description "redis basic commands for caching" likes 20 visitors 23000
OK
redis 127.0.0.1:6379> HGETALL w3ckey
1) "name"
2) "redis tutorial"
3) "description"
4) "redis basic commands for caching"
5) "likes"
6) "20"
7) "visitors"
8) "23000"
1 HSET key field value 将哈希表 key 中的字段 field 的值设为 value 。
2 HGET key field 获取存储在哈希表中指定字段的值/td>
3 HGETALL key 获取在哈希表中指定 key
4 HDEL key field2 [field2] 删除一个或多个哈希表字段
HMGET key field1 [field2] 获取所有给定字段的值
HMSET key field1 value1 [field2 value2 ] 同时将多个 field-value (域-值)对设置到哈希表 key 中。
命令文档:https://www.redis.net.cn/tutorial/3509.html
List(列表)
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
实例
redis 127.0.0.1:6379> LPUSH w3ckey redis
(integer) 1
redis 127.0.0.1:6379> LPUSH w3ckey mongodb
(integer) 2
redis 127.0.0.1:6379> LPUSH w3ckey mysql
(integer) 3
redis 127.0.0.1:6379> LRANGE w3ckey 0 10
1) "mysql"
2) "mongodb"
3) "redis"
![image-20210519142230628](https://gitee.com/qhzeng/markdown/raw/master/image/image-20210519142230628.png)
添加
LPUSH key value1 [value2] 将一个或多个值插入到列表头部(左边)
RPUSH key value1 [value2] 在列表中添加一个或多个值(右边)
LPUSHX key value 将一个或多个值插入到已存在的列表头部
RPUSHX key value 为已存在的列表添加值
删除
LPOP key 移出并获取列表的第一个元素(删除最左边)
RPOP key 移除并获取列表最后一个元素(删除最右边边)
获取
LRANGE key start stop 获取列表指定范围内的元素(获取所有,0 到 -1)
命令文档:https://www.redis.net.cn/tutorial/3510.html
Set(集合)
Redis的Set是string类型的无序集合。——存入和取出的数据不一致
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
实例
redis 127.0.0.1:6379> SADD w3ckey redis
(integer) 1
redis 127.0.0.1:6379> SADD w3ckey mongodb
(integer) 1
redis 127.0.0.1:6379> SADD w3ckey mysql
(integer) 1
redis 127.0.0.1:6379> SADD w3ckey mysql
(integer) 0
redis 127.0.0.1:6379> SMEMBERS w3ckey
1) "mysql"
2) "mongodb"
3) "redis"
存储
SADD key member1 [member2] 向集合添加一个或多个成员
成功返回1,如果元素以及在集合中返回0,key对应的set不存在返回错误。
获取元素
SMEMBERS key 返回集合中的所有成员
删除
SREM key member1 [member2] 移除集合中一个或多个成员
命令文档:https://www.redis.net.cn/tutorial/3511.html
Zset(sorted set:有序集合)
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
zset的成员是唯一的,但分数(score)却可以重复。
实例
redis 127.0.0.1:6379> ZADD w3ckey 1 redis
(integer) 1
redis 127.0.0.1:6379> ZADD w3ckey 2 mongodb
(integer) 1
redis 127.0.0.1:6379> ZADD w3ckey 3 mysql
(integer) 1
redis 127.0.0.1:6379> ZADD w3ckey 3 mysql
(integer) 0
redis 127.0.0.1:6379> ZADD w3ckey 4 mysql
(integer) 0
redis 127.0.0.1:6379> ZRANGE w3ckey 0 10 WITHSCORES
1) "redis"
2) "1"
3) "mongodb"
4) "2"
5) "mysql"
6) "4"
插入
ZADD key score1 member1 [score2 member2] 向有序集合添加一个或多个成员,或者更新已存在成员的分数
删除
ZREM key member [member ...] 移除有序集合中的一个或多个成员
获取
ZRANGE key start stop [WITHSCORES] 通过索引区间返回有序集合成指定区间内的成员
命令文档:https://www.redis.net.cn/tutorial/3512.html
通用命令
keys * 查询所有的键
type key 查询对应的value类型
del key 删除指定的key value
![image-20210519145207307](https://gitee.com/qhzeng/markdown/raw/master/image/image-20210519145207307.png)
持久化
-
redis是一个内存数据库,当redis服务器重启,获取电脑重启,数据会丢失,我们可以将redis内存中的数据持久化保存到硬盘的文件中。
-
redis持久化机制:
RDB:
原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化
默认方式,不需要迸行配置,默认就使用这种机制
在一定的间隔时间中,检测key的变化情况,然后持久化数据
1.编辑redis.windwos.conf文件after 900 sec (15 min) if at least 1 key changed
save 900 1
after 300 sec (5 min) if at least 10 keys changed
save 300 10
after 60 sec if at least 10000 keys changed
save 60 10000
2 .重新启动redis服务器,并指定配置文件名称
AOF :
![image-20210519152241441](https://gitee.com/qhzeng/markdown/raw/master/image/image-20210519152241441.png)
原理是将Reids的操作日志以追加的方式写入文件
日志记录的方式,可以记录每一条命令的操作。可以每一次命令操作后,持久化数据
1 .编辑redis .windwos. conf文件
appendonly no (关闭aof) --> appendonly yes (开启aof)
appendfsync always 每一次操作都进行持久化
appendfsync everysec 每隔一秒进行一次持久化
appendfsync no 不进行持久化
![image-20210519151314730](https://gitee.com/qhzeng/markdown/raw/master/image/image-20210519151314730.png)
两者的区别:https://www.cnblogs.com/zxs117/p/11242026.html
3、二者优缺点
RDB存在哪些优势呢?
1). 一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
2). 对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。
3). 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。
4). 相比于AOF机制,如果数据集很大,RDB的启动效率会更高。
RDB又存在哪些劣势呢?
1). 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
2). 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。
AOF的优势有哪些呢?
1). 该机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确的理解它。
2). 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。
3). 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。
4). AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。
AOF的劣势有哪些呢?
1). 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
2). 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。
二者选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再做备份(rdb)。rdb这个就更有些 eventually consistent的意思了。不过生产环境其实更多都是二者结合使用的。
Jedis
类似于JDBC
Jedis操作数据
https://www.runoob.com/redis/redis-java.html
public class RedisStringJava {
public static void main(String[] args) {
//连接本地的 Redis 服务 Jedis jedis=new Jedis(); 空参:默认本地
Jedis jedis=new Jedis("localhost",6379);
System.out.println("连接成功");
//操作数据
jedis.set("username","zqh");
String username = jedis.get("username");
System.out.println(username);
//关闭连接
jedis.close();
}
}
Jedis连接池
配置文件
jedis.properties
maxTotal=50
maxIdle=10
host=127.0.0.7
port=6379
工具类:
JedisUtill
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class JedisUtill {
//创建Properties对象
private static Properties properties = new Properties();
//读取配置文件
private static JedisPoolConfig config = new JedisPoolConfig();
private static JedisPool pool;
private JedisUtill() {
}
static {
//读取配置文件
InputStream inputStream = JedisUtill.class.getClassLoader().getResourceAsStream("jedis.properties");
try {
properties.load(inputStream);
//获取数据,设置到JedisPollConfig中
config.setMaxTotal(Integer.parseInt(properties.getProperty("maxTotal")));
config.setMaxIdle(Integer.parseInt(properties.getProperty("maxIdle")));
//初始化连接池pool
pool = new JedisPool(config, properties.getProperty("host"), Integer.parseInt(properties.getProperty("port")));
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static Jedis getResource() {
return pool.getResource();
}
public static void close(Jedis jedis) {
if (jedis != null) {
jedis.close();
}
}
public static void shutdown() {
if (pool != null) {
if (pool.getNumActive() == 0) {
pool.close();
}
}
}
}
测试代码
@Test
public void test02(){
Jedis jedis =JedisUtill.getResource();
jedis.set("hello","zqh");
System.out.println(jedis.get("hello"));
jedis.close();
}
}
public static void close(Jedis jedis) {
if (jedis != null) {
jedis.close();
}
}
public static void shutdown() {
if (pool != null) {
if (pool.getNumActive() == 0) {
pool.close();
}
}
}
}
测试代码
@Test
public void test02(){
Jedis jedis =JedisUtill.getResource();
jedis.set("hello","zqh");
System.out.println(jedis.get("hello"));
jedis.close();
}