NoSql数据库

Posted coderlin_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NoSql数据库相关的知识,希望对你有一定的参考价值。

NoSql数据库,非关系型

  • 易扩展,高性能,高可用
  • 较容易映射复杂数据(key-value)
  • 无事务特性要求(ACID特性)

NoSQL设计

  • 常见的场景及设计方法(内嵌,父子引用,反范式)
  • 双向关联的场景及设计原则。

内嵌

存在关联关系的文档,放在同一文档中,以数组的形式存放。

  • 减少了关联查询,只需要一句sql语句就可以查询很多数据
  • 适合单类需要描述的属性
  • 不经常变化的属性(扩展,嵌套关联)

父子引用

  • 父引用是指存在一对多的情况中,放在同一文档中,以数组的形式存放。

    课程对应的多个课程ID,以数组形式存放。
  • 子引用是指存在一对非常多的情况中,由于数据库文档存放限制,使用反向引用。

    课程ID存储在cid上。
    父子引用设计:
  • 引用数据内容是否非常多
  • 引用数据量是否非常庞大,而且在增加
  • 数据是否需要单独访问

反范式

  • 范式是指按既定的用法,范式就是一种公认的模型或者模式。反范式=》不走寻常路

    不创建用户表,将用户数据直接塞入users中。
    反范式设计:
  • 是否有提升性能的区间
  • 数据量的变化是否非常庞大,庞大到更新会异常低效。
  • 先考虑读写比,才考虑反范式,如果需要经常读写,就不适用。

Redis数据库

高性能key-value数据库。支持数据持久化,多数据结构,list,set等的存储,支持数据备份。
特点

  • 高性能,持久化
  • kye-value结构,支持多种数据类型
  • 支持事务,数据的原子性(要么做,要么不做)
    应用场景:
  • 缓存(读写性能优异)
  • 计数和消息系统(高并发,发布、订阅阻塞队伍功能)、

Redis存储结构

Redis以字典结存储数据,并允许其他应用通过TCP协议读写字典中的内容。

direct[key] = value

Rdis字典中的键值除了可以是字符串,还可以是其他数据类型,比如hash,list,Set, ZSet等

内存存储与持久化

Redis数据库中所有数据都存储在内存中,读写速度更快,通常用redis做缓存数据库。
存储在内存中可以回导致程序退出导致数据丢失,但是redis提供了持久化支持,即可以将内存中的数据异步写入到硬盘中。

功能丰富

redsi虽然作为数据库开发,但是其提供了丰富的功能。如

  • 作为缓存系统。Redis可以为每个键设置生存时间,过期自动删除。可以限定数据占用最大空间,达到限制后按照一定规则自动淘汰不需要的键。
  • 作为队列系统。Redis的列表类型键可以用来实现队列,支持阻塞式读取。实现一个高性能优先级队列。
  • 发布订阅功能。Redis支持发布订阅的消息模式,可以基于此构建聊天室等系统。

简单稳定

对于sql语句,从posts表获取id为1的纪律

SELECT title FORM posts WHERE id=1 LIMIT 1

对于redis命令行,取键名为post:1的hash的title字段的值

HGET post:1 title

应用场景

  • 缓存系统。
  • 排行榜,如京东的月度销量榜单
  • 计数器,比如视频网站的播放次数等等。
  • 分布式会话。session不再由容器管理,而是由redis搭建的session服务及内存数据库管理。
  • 分布式锁、
  • 社交网络。点赞,踩等功能。
  • 最新列表。LPUSH可以在列表头部插入,LTIRM可以用来限制列表数量。这样列表永远为N个,无需查询。
  • 消息系统,Redis提供简单的消息队列系统。

docker安装redis

可以docker-compose.yml

version: '3'
services:
  redis-test:
    image: "redis"
    restart: "always"
    container_name: "redis-test"
    ports:
      - 15001:6379
    volumes:
      - /home/redistest:/data
    command: ["redis-server", "--requirepass", "123456"]

也可以通过命令行的方式

dokcer run -itd  --restart=always  --name redis-test -p 15001:6379 -v /home/redistest:/data redis redis-server --requirepass=123456

Redis中的多数据库

Redis默认支持16个数据库,分别是0,1,2…15.

  • Redis不支持自定义数据库名字。
  • 每个数据库都以编号命名。
  • 可以通过配置参数databases修改支持的数据库个数。

Redis常见cli命令行工具

Redis不是简单的键值存储,实际上,他是一个数据结构服务器,支持不同类型的值。字符串补给你可以关联字符串,还可以关联Hash,List, Set, ZSet, Bit arrays等等。
参考网站
进入reids容器

 docker exec -it redis-test /bin/bash
 redis-cli

密码登录

127.0.0.1:6379>  auth xxx(密码)
Redis中的键

Redis密钥是二进制的,这也就意味着可以使用任何二进制序列作为key。从字符串到JPEG文件的内容,空字符串也是有效的键。

Redis的数据类型
字符串
  • 可以存储任何形式字符串,包括二进制。
  • 可以存储用户邮箱,JSON化的对象,甚至一张图片。
  • value最多可以容纳数据大小为512MB。
  • 字符串是其他四种常见数据类型的基础。比如列表类型就是以列表的形式组织字符串…

设置

SET key value  //设置值
GETSET key value //设置值,并返回key旧值
SHTNX key value // 当key不存在才会创建
MSET key value [key value ...] // 同时设置多个
MSETNX key value [key value] //当指定key不存在才会创建。 支持多个。
APPEND key value

查询

get key //查看key
getrange key 0 3 //返回key字符串的0到3的字符
mget key [key..]  //获取多个key
strlen key //key的长度
exists key [key..] //是否有指定的key
type key //key的类型
Redis的数字值

数字值在Redis中以字符串保存。

incr key // Key+1
incrby key 3 //Key+3
incrbyfloat key 3 //Key+3浮点数
decr key // Key-1
decrby key 3 //Key -3 
哈希(HASH)

哈希类型是一种字典结构,可以存储字段和字段值的映射,但是字符值只能是字符串,不能是其他数据类型。

const user = 
name: 'jacl',
age: 12

usr就是键,name是字段,jacl是字段值的映射。

hset key field value [field value ...] // 设置user,字段field ,值为value
hmset key field value  [field value ...] // 同时设置多个
hsetnx key field value // 只有field不存在才会设置

查询

hkeys key //查看key的所有字段
hlen key // 查看key字段数量
hmget key field1 [field2...] //获取所有给定字段的值
hget key field
hgetall key //全部字段和值
hexists key field //判断key的field字段存在?
hvals key // key的所有值
hscan key cursor [MATCH pattern] [COUNT coun] //迭代哈希表中的键值对

修改

hsset key field value [field value...] 
hincrby key field 3 //为key的field字段+3

删除

hdel key field [field]
DEL key [key..] //删除整个HASH
列表list

类似于数组,可以存储一个有序的字符串列表。常用的就是向列表两端添加元素。获取列表的某个字段。
内部使用双向链表实现,所有向列表两端添加元素的时间复杂度为o(1),查找两端也是非常快,很适合像新鲜事这些。

lpush key element[element ...] 插入到列表头部  比如a,b,c。那么顺序就是c b a 。 先插入的就到最后面
linsert key before|after pivot value 在某个元素前后插入元素
lpushx key value 将value插入到头部
lset key index value 通过索引设置值
rpush key value [value2] 添加多个值 往右边也就是后面插,
rpushx key value 为已存在的列表添加值。

查询

lindex key index  索引
llen key //长度
lrange key start stop  范围

删除

lpop key //从左侧删除第一个元素并返回
rpop key //删除最后一个并返回。
lrem key count 2
// count > 0,从头向尾遍历删除值为2,删除最大次数是count个。count = 0 删除所有匹配个元素。
// count < 0,从后面开始匹配删除值为2的,删除最大次数是count个
集合

集合类型和数学中的集合概念相似。集合中的元素是唯一的,无序的,简单理解就是没有顺序且不重复的列表。一个集合类型可以存储至多2的32次方-1个字符串

  • 列表是有序的,集合是无序的。
  • 列表数据可以重复,集合中没有重复数据。
  • 集合在redis内部使用值为空的散列表(hash)实现的,操作的时间复杂度都是o(1)
  • 最方便的是多个集合可以进行并集,交集和差集运算。

添加

sadd key merber1 [merber2]

查询

smebers key //返回key所有成员
scard key //成员数
sismember key member //判断member是否是key的成员
srandmember key [count] //返回集合中一个或者多个随机数。

删除

srem key member1 [member2...]
spop key //删除随机元素并返回
smove a  b member //从a往b中,将member移到b
集合间运算

并集,交集,差集。

sdiff key1 [key2] // 差集
sinter key1 [key2] 交集
sunion key1 [key2] 并集
sdiffstore a key1 [key2] // 差集存储到a
sinterstore a key1 [key2] // 交集到a
sunionstore a key1 key2 //并集到a
集合使用场景
  • 跟踪唯一性数据。比如访问网站的唯一ip地址信息。
  • 充分利用set聚合操作方便搞笑的特性,维护数据对象之间的关联关系。如所有购买A商品的客户ID存储到指定的SET中,购买B的存储到SET2中,取交集就可以轻松查找购买A和购买B的人
有序集合

有序集合是一中类似集合和哈希之间的混合数据类型。

  • 与集合一样,有序集合由唯一的非重复性字符串元素组成。
  • 有序集合中的元素不排序,但是,有序集合的每个元素关联一个分数,分数是有序的。
  • 虽然集合中每个元素都是不同的,但是他们的分数可以相同。如
键 --->   张三(元素)  -> 10 (分数)
	--->  李四(元素) -> 15 (分数)

与列表对比:

  • 两者都是有序的,两者都可以获取某一范围的元素。
  • 列表类型通过链表实现,获取靠近两端的数据速度极快,访问中间就慢,适合新鲜事
  • 有序集合类似使用哈希表实现的,读取中间部分的数据也很快。
  • 列表中不能简单地调整某个元素的位置,但是有序集合可以。通过改变分数。
  • 有序集合比列表更耗费内存。

有序集合典型场景:

  • 排行榜
  • 微博热搜

添加 Z开头

zadd key score member [ socre member] 向有序集合添加一个或多个成员,或者更新分数

查询

zrange key start stop WITHSCORES,读取key的start到stop位置的成员,默认分数从递到高排序,
zrevrange key start stop WITHSCORES,从高到底排序
zrangebyscore key 60 90 //查询key中分数60-90的成员 低到高
zrevragebyscore key 60 90 //高到低
zrank key a // a的排名,从低到高
zrevrank key a // 从高到低
zcard key //个数
zscore key member // 查看分数
zcount key min max //计算min到max中有多少个。

修改

zadd key score member [ score member ...]
zincrby key 3 member // 往key中的member的分数加3 

删除

zrem key member
zremrangebyrank key start stop //删除指定区间从低到高排名
zremrangebyscore key min max //删除指定分数的成员
通用命令
keys *// 返回所有key
keys my*  返回以my开头的key
exists key key ...  判断存在
rename key newkey  重命名
randomkey //随即返回一个key
flushdb 清空当前数据库所有美容
flushall 清空所有数据库内容
设置过期时间

在redis中可以设置一个键的过期时间,到时间后,Redis会自动删除它。

expire key 10 // key 10s
pexire key 10 // kee 10ms
expireat key timestamp // 时间戳
pexpireat key milliseconds-timestamp
  • 前三个最终都会使用pexpireat 来执行。
  • 如Expire设置,调用Pexire将n转为m毫秒。获取当前的Unix时间单位,将当前的时间单位加上m毫秒传递给pexpireat
  • 给键设置过期时 间,时间保存在字典了,也是键值结构。
ttl key //以秒为单位,返回剩余时间
pttl key //毫秒

如果 返回-2,过期且删除。-1,没有过期时间。

persist key //清除过期时间

使用set或者getset命令为键赋值,会同时清除键的过期时间,其他操作不会,如Incr, Lpush。

Redis事务 ACID

  • A (Atomicity)原子性,事务要么全部完成,要么全部取消,如果事务崩溃,状态将回到事务之前(事务回滚)
  • I (lsolation)隔离性,如果2个事务,T1和T2同时执行,事务T1 T2的最终结果是相同的,不管谁先执行完毕。
  • D 持久性 一旦事务提交,不管发生什么,数据要保存在数据库。
  • C 一致性 只有合法的数据,才能写入数据库。
命令
multi			标记一个事务块的开始,可以开始编写命令了
exec 			执行所有事务块内的命令

127.0.0.1:6379> set jack 10
OK
127.0.0.1:6379> set rose 20
OK
127.0.0.1:6379> multi  //开始事务
OK
127.0.0.1:6379(TX)> decrby jack 5  //命令入队
QUEUED
127.0.0.1:6379(TX)> incrby rose 5  //命令入队
QUEUED
127.0.0.1:6379(TX)> exec   // 执行事务
1) (integer) 5
2) (integer) 25

discard 		取消事务,放弃事务块内所有命令
事务中的错误处理

事务块中的命令出错

  • 1 语法错误,错误之后会直接报错,有语法错误的命令,事务不会执行。
  • 2 运行错误,如果一条命令运行的时候错误了,其他命令依然会执行。
事务中的WATCH命令

WATCH定义:监视一个或者多个key,在事务执行之前若这个key被其他命令所改动,那么事务将被打断。

watch key [key..]
unwatch

Redis持久化

  • RDB方式的持久化通过快照完成。当符合一定条件时,Redis会自动将内存中的所有数据生成一份副本并存储在硬盘上,这个过程即为快照。
  • 两个参数,时间窗口M和改动的键的个数N,当时间M内,更改键的个数大于N的时候,即符合自动快照条件。

redis的默认配置

save 900 1 //900s内之至少有1个key变化了,则写入快照
save 300 10 // 300秒内至少有10个key变化了,则写入快照
save 60 10000 
dbfilename dump.rdb // 快照保存的文件名称 
dir ./   //快照文件保存路径

RDB快照的运行方式是异步进行的,在保存快照期间依然能够提供客户端端请求。
fork一个子进程,原来的redis进程继续处理客户端,子进程负责将数据保存到磁盘,然后退出

AOF持久化

  • 快照并不是非常持久,如果redis因为某些原因造成故障,那么服务器将丢失最近写入,且仍未保存到快照的哪些数据。
  • 对于追去完全持久化的程序,快照就不太实用了。
  • AOF可以将Redis执行的每一条写命令操作日志,存储到硬盘文件中,
  • AOF机制对于日志的写入操作是append模式,追加模式
  • 默认没有开启AOF,可以通过appendonly yes开启
  • AOF文件的保存位置和RDB文件位置相同,默认是appendonly.aof,可以通过appendfilename 'xxx’来修改。
AOF三种同步策略
appendfsync always 每一次数据变化,都会同步到硬盘中。
appendfsync everysec 每一s再同步
appendfsync no 关闭AOF

默认是appendfsync everysec 。

AOF对比RDB

RDB优点:

  • 文件小
  • 异步备份,性能好
  • 恢复大数据集速度比AOF块。

缺点:

  • 数据安全性低,容易丢失。
  • 数据量比较大的时候备份速度满。

AOF优点:

  • 数据安全性高
  • 有利于开发分析

缺点:

  • 相同数据比RDB文件大。
  • 根据所使用的fsync策略,AOF的速度可能会慢于RDB。

使用node.js操作redis

  • ioredis库。支持集群,前哨,流,流水线等。高性能。异步API…
import Redis from 'ioredis'

// 建立连接
const redis = new Redis(
    port: '15001',
    host: "106.55.237.178",
    password: "123456",
 as any)

// 操作
// redis.set('testtest', 'hahaha', (err, result)=>
//     if(err)
//         console.log('操作失败');
//         return 
//     
//     console.log('操作成功');
//     console.log(result);
// )
async function main()
    const res = await redis.get('testtest')
    console.log('res', res);
    


main()
管道Pipelining

如果要发送一批命令,则可以使用流水线将命令在内存中排队,然后一次全部打送到Redis。

  • redis.pipeline()创建一个Pipeline实例。在实例上调用任何redis命令,这些命令会在内存中排队,哦通过调用exec方法发送给REdis。有点像事务操作,但他只是Redis提供的客户端功能。

const pipe = redis.pipeline()

pipe.set('hahah', 'fiii')
pipe.get('hahah', (err, result)=>
    console.log(result);
)

pipe.exec()
// 还可以
redis.pipeline().set('test19', 'hahahah').del('hahah').get('hahah',(err, result)=>
    console.log('result', result);
).exec()
事务操作

事务命令multi和exec一般与管道一起使用。因此,在调用multi的时候,默认会创建pipeline实例,因此可以像使用管道一样使用multi、

redis.multi().set('test20', 'hahahah').del('test19').get('test20',(err, result)=>
     console.log('result', result);
 ).exec()
//result QUEUED返回值,不跟管道一样,事务每个链接的回调是将排队状态传递给回调,而不是结果、

如果有语法错误,不会执行。

  • 要使用不带管道的事务,就要添加pipeline:false,那么每个命令将立即发送给Redis,无需等待exec调用。
  • 内联事务
 redis.pipeline().get('foo').multi().set('foo', 'bar').get('foo').exec().get('foo').exec()
错误处理

使用node操作mongodb


node操作Mongodb基本操作

const mongoose = require("mongoose");

mongoose.connect(
  "mongodb://账号:密码服务器地址:27017/blob?authSource=admin",
   useNewUrlParser: true 
);

const User = mongoose.model("users", 
  name: String,
  age: Number,
  email: String,
);
const test = new User( name: "123", age: 12, email: "123" );
test.save().then(() => 
  console.log("save Ok!");
);


以上是关于NoSql数据库的主要内容,如果未能解决你的问题,请参考以下文章

NoSQL 简介

NOSQL介绍

一文深入浅出NoSQL数据库

天天在讲的 NoSQL 数据库到底是个什么鬼?

独家一文读懂非关系型数据库(NoSQL)

面试高频:SQL vs NoSQL