redis非关系数据库
目录
- NOSQL的概念
- NOSQL和RDBMS的区别。
- 常见的NOSQL数据库类型
- 什么是redis
- 为什么使用redis
- 如何安装redis
- redis可视化工具—RedisPlus
- redis支持的数据类型以及它对应类型下的命令
- List 队列类型 和 set集合类型 sortSet 有序集合
- Redis的持久化方式。
- redis集群的搭建。
(1)主从模式
(2)哨兵模式
(3)去中心集群。 - redis的集群的其他模式
(1)哨兵模式:
(2)去中心化集群 - Java连接redis.
- springboot整合redis
1.NOSQL的概念
NOSQL(Not only sql):不仅是sql语句, 它是对所有非关系型数据库的一种统称。 除去关系型数据库之外的都是非关系数据库。
2. NOSQL和RDBMS的区别
RDBMS
- 高度组织化结构化数据。 user—userid username age sex …
- 结构化查询语言(SQL) sql语句
- 数据和关系都存储在单独的表中。
- 数据操纵语言DML,数据定义语言DDL
- 严格的一致性. 事务
- 基于事务
NoSQL - 代表着不仅仅是SQL
- 没有声明性查询语言
- 键 - 值对存储。
- 最终一致性,而非ACID【原子,一致,隔离,持久】属性
- 非结构化和不可预知的数据 字符串 对象 队列 集合
- 高性能,高可用性和可伸缩性。 适合搭建集群。 mysql搭建集群。非常复杂。主从模式
NOSQL是替换RDBMS的吗? 不是。
3. 常见的NOSQL数据库类型
Redis就属于非关系数据库。
Mongodb属于非关系数据库。----接近mysql数据库
4. 什么是redis。
Redis是一种开放源代码(BSD许可)的内存中数据结构存储,用作数据库,缓存和消息代理。Redis提供数据结构,例如字符串,哈希,列表,集合,带范围查询的排序集合,位图,超日志,地理空间索引和流。Redis具有内置的复制,Lua脚本,LRU驱逐,事务和不同级别的磁盘持久性,并通过Redis Sentinel和Redis Cluster自动分区提供了高可用性。
Redis是一个开源的使用ANSI C语言编写可基于内存亦可基于磁盘,Key-Value数据库。类似于map
5. 为什么使用redis
1.Redis读取的速度是110000次/s,写的速度是81000次/s
2.原子 。Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。
3.支持多种数据结构:string(字符串);list(列表);hash(哈希),set(集合);zset(有序集合)
4.持久化–磁盘,主从复制(集群)
5.官方不支持window系统,但是又第三方版本。 linux系统。
6.如何安装redis.
准备工作
1.安装redis需要的环境。yum install -y gcc-c++
2.上官网下载redis源码安装包。
redis-5.0.8.tar.gz
安装步骤
1. 解压redis到/usr/local
2. 进入redis目录并执行编译命令 make
3. 执行安装命令 make install
开启redis服务。
redis-server redis.conf
使用redis客户端连接redis服务器
redis-cli -h redis服务器的ip -p redis服务器的端口号
redis配置文件简单看看
# 表示启动redis服务器时 后台启动。
daemonize yes
# 默认的端口号。
port 6379
# 默认运行绑定的端口号~~~~~~~~~~~~~~~~~~~~~~~HTTP协议~~~~~~~~~~~~~~~~~
# bind 127.0.0.1
# 0.0.0.0 表示广播模式 意思是所有人都可以连接。
bind 0.0.0.0
7. redis图形化界面的客户端
8. redis支持的数据类型一技对应类型下的命令。
8.1 对key操作的命令
keys *: 查询所有的key;
del key....:删除指定的key
expire key seconds: 为指定的key设置过期时间单位为秒
ttl key: 查询指定key的存活时间
8.2 对数据库的操作命令
flushdb: 清空当前数据库中的数据。
select index: 选择数据库
flushall: 清空所有数据库中的数据。
8.3 redis支持的数据类型
http://www.redis.net.cn/order/
http://redisdoc.com/
1. String字符串类型
2. Hash 哈希类型
3. list 队列
4. set 集合
5. sorted set 有序集合。
8.4 String字符串类型–value值为字符串类型
可以存放任意类型的字符串。java对象—>json字符串—>string
set key value: 把字符串的value存放到对应的key上。
get key: 根据指定的key获取对应字符串的value
mset key value key value key value....: 一次存放多个字符串的value到相应的key上
mget key key...: 根据指定的多个key获取对应的字符串的value
setnx key value: 把指定的value存放到对应的key上,如果对应的key已经存在,则不存储。
如果不存在则存储。 返回0或者1
incr key: 为指定的key的value值进行递增。应用场景:点赞 收餐 转发等
decr key: 递减
8.5 Hash 类型。–value值为hash类型。
hset key field value: 存放一个指定key的field-value的数据库
hget key field:获取指定key的field字段对应的value值。
hkeys key: 获取指定key的所有field字段名
hvals key: 获取指定key的所有value值。
hgetall key: 获取指定key的所有的field和value值。
HDEL key field: 删除指定key的field字段。
9. List 队列类型 和 set集合类型 sortSet 有序集合
9.1 List队列类型
lpush: 将一个或多个值 value 插入到列表 key 的表头.
lpop: 移除并返回列表 key 的头元素。
lrange: 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。
9.2 set集合
sadd key value.....: 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
spop key: 移除并返回集合中的一个随机元素。
smove source destint member:
smembers key:获取指定key下的所有的元素
sinter key key ...:求所有集合的交集。
9.3 sortSet 有序集合。
应用场景: 排行耪
1.zadd key score value score value ....:添加有序集合元素。
2.zrange key start end: 获取指定返回的元素。
10. Redis的持久化方式。
持久化:把内存中的数据库保存到磁盘上。防止数据的丢失。
redis支持的持久化方式两种:
(1)RDB:快照 其实就是把数据以快照的形式保存在磁盘上,什么是快照呢,你可以理解成把当前时刻的数据拍成一张照片保存下来。
(2)AOF:日志追加 记录服务器接受的每个写入操作,当服务器启动时再次加载该日志,会把日志中的命令重新执行一遍。
(1) RDB快照持久化方式
1.1 如何触发RDB持久化
1. 手动save命令
2. 手动bgsave命令
3. 通过配置自动触发。
1.2 save和bgsave区别
该命令会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他命令,直到RDB过程完成为止。具体流程如下:
、
执行完成时候如果存在老的RDB文件,就把新的替代掉旧的。我们的客户端可能都是几万或者是几十万,这种方式显然不可取。
执行该命令时,Redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。具体流程如下:
自动触发:
1.3 保存在磁盘上后,该文件的名字叫什么?
1.4 恢复数据
只需要把dump.rdb文件放入redis的安装目录即可,redis再次启动时回加载安装目录下的dump.rdb文件。
1.5 rdb的优缺点
优点:
(1)RDB文件紧凑,全量备份,非常适合用于进行备份和灾难恢复。
(2)生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。
(3)RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
缺点:
快照持久化期间修改的数据不会被保存,可能丢失数据。数据完整性比较差。
(2)AOF模式
2.1 AOF 默认该模式是关闭的。
提供一种更加高效的方式AOF,工作机制很简单,redis会将每一个收到的写命令都通过write函数追加到文件中。通俗的理解就是日志记录。
aof的触发模式
优缺点:
优点:
(1)AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据。
(2)AOF日志文件没有任何磁盘寻址的开销,写入性能非常高,文件不容易破损。
(3)AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。
缺点:
(1)对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大.
(2) 恢复数据时时间要比快照模式慢很多。
11. redis集群搭建
(1)主从关系
配从不配主
准备工作:
1. 创建了一个目录 master-slave
2. 把redis配置文件复制到master-slave
redis7001.conf redis7002.conf redis7003.conf
3.分别修改上面三个文件的端口号以及rdb持久化文件的名称 并aof关闭。
4. 启动redis时指定上面的三个配置文件
查看三个redis节点的信息
我们在7002和7003使用slaveof 127.0.0.1 7001 把7002和7003挂载7001上
特点:
1.主节点负责写,并把写的内容同步到从节点上。 从节点只能负责读操作。不能写操作。
主节点挂掉,从主节进入等待状态, 等待主节点上线。
如果这时,有一个新得节点加入到主从上了,新节点不可以把之前得数据获取。
(2)哨兵模式
修改sentinel.conf的配置
# 127.0.0.1表示redis主节点的ip
# 6379 表示主节点的端口号
# 2 表示有多少个哨兵选取redis从节点后,该从节点可以当选为主节点。
sentinel monitor mymaster 127.0.0.1 7001
启动哨兵
redis-sentinel sentinel.conf
(3)去中心化集群。
哨兵的缺点
1. 没有解决单节点的问题。
2. 持久化文件始终在一个服务器上。
去中心化
port 8001
bind 0.0.0.0
daemonize yes
appendonly yes
# 开启集群
cluster-enabled yes 833行
# 集群的配置文件,该文件自动生成
cluster-config-file nodes-8001.conf 841行
# 集群的超时时间
cluster-node-timeout 5000 847行
启动所有的redis
为主节点分配槽以及分配从节点
cluster-replica:每个主节点跟随的从节点的个数
redis-cli --cluster create --cluster-replicas 1 192.168.31.98:8001 192.168.31.98:8002 192.168.31.98:8003 192.168.31.98:8004 192.168.31.98:8005 192.168.31.98:8006
必须保证aof开启,保证redis中没有数据。
客户端访问:
redis-cli -c -h 192.168.31.98 -p 8001
13. Java连接redis.—jedis
(1)依赖
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.3.0</version>
</dependency>
</dependencies>
(2)操作
package com.kh.test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import java.util.Set;
public class TestJedis {
public static void main(String[] args) {
Jedis jedis=new Jedis("192.168.31.98",6379);//必须运行远程连接 必须防火墙放行该端口号
//关于字符串
jedis.set("k1","v1");
jedis.set("k8","18");
jedis.mset("k2","v2","k3","v3","k4","v4");
jedis.setnx("k1","12");
jedis.decr("k8");
//操作key
Set<String> keys = jedis.keys("*");
System.out.println("所有的key:"+keys);
jedis.del("k1");
jedis.expire("k2",60);
jedis.ttl("k2");
}
}
使用jedis连接池
package com.kh.test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class TestPoolJedis {
public static void main(String[] args) {
//连接池的配置
JedisPoolConfig config=new JedisPoolConfig();
config.setMaxTotal(100);//设置连接池的最大连接数
config.setMaxIdle(10);//设置最大空闲的个数
config.setTestOnBorrow(true);//在从连接池这种获取连接对象前是否测试该对象可以。
//创建连接池对象
JedisPool jedisPool=new JedisPool(config,"192.168.31.98",6379);
//获取jedis对象
Jedis jedis = jedisPool.getResource();
System.out.println(jedis.get("k3"));
jedis.close();//释放资源
}
}
6. springboot整合redis
springboot为操作redis准备了两个工具类StringRedisTemplate和RedisTemplate。StringRedisTemplate是RedisTemplate的子类。StringRedisTemplate它的泛型key和value都是String类型。 RedisTemplate它的key value的泛型是Object。
步骤:
(1)引入依赖
<!---->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
(2) 配置
spring.redis.host=192.168.31.98
spring.redis.port=6379
spring.redis.jedis.pool.max-active=20
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.min-idle=0
spring.redis.jedis.pool.max-wait=20000
(3)测试
package com.kh.springbootredis01;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
@SpringBootTest
class SpringbootRedis01ApplicationTests {
@Autowired
private StringRedisTemplate redisTemplate;
@Test
void contextLoads() {
//操作key
Set<String> keys = redisTemplate.keys("*");
System.out.println(keys);
redisTemplate.delete("k8");
System.out.println(redisTemplate.getExpire("k3"));
redisTemplate.expire("k3", 60, TimeUnit.SECONDS);
System.out.println(redisTemplate.getExpire("k3"));
}
@Test
public void testString(){
ValueOperations<String, String> forValue = redisTemplate.opsForValue();//操作字符串类型
forValue.set("k1","v1");
System.out.println(forValue.get("k1"));
Map<String,String> map=new HashMap<>();
map.put("k9","v9");
map.put("k10","v10");
forValue.multiSet(map);
List<String> keys=new ArrayList<>();
keys.add("k1");
keys.add("k2");
keys.add("k4");
List<String> strings = forValue.multiGet(keys);
System.out.println(strings);
System.out.println(forValue.setIfAbsent("k2", "v2"));
}
}