Python NoSQL数据库操作

简介

NoSQL指的是非关系型数据库,用于超大规模数据的存储。这类数据库一般存储的是非结构化数据,如key-value、文档、图像等不需要固定模式,无需多有操作就可以横向扩展。

CAP定理

在计算科学中,CAP定理又称为布鲁尔定理,它指的是对于一个分布式系统来说,不可能同时满足以下三点:

  • 一致性(Consistency)所有节点在同一时间具有相同的数据
  • 可用性(Avaliability) 保证每个请求不管成功或者失败都有响应
  • 分隔容忍(Partition tolerance)系统中任意信息的丢失或失败都不会影响系统的继续运作

CAP原理核心是一个分布式系统不可能同时很好满足一致性、可用性和分区容错性三个需求,最多只能同时较好的满足两个。因此根据CAP原理将NoSQL数据库分成满足CA原则、满足CP原则和满足AP原则三大类:

  • CA:单点集群,妈祖一致性、可用性的系统,通常在可扩展性上不太强大
  • CP:满足一致性、分区容忍性的系统,通常性能并不是特别高
  • AP:满足可用性,分区容忍性的系统,通常可能对一致性要求低一些

NoSQL分类

类型部分代表特点
列存储Hbase、Cassandra、Hypertable顾名思义,是按列存储数据的。最大的特点是方便存储结构化和半结构化数据,方便做数据压缩,对针对某一列或者某几列的查询有非常大的IO优势。
文档存储MongoDB、CouchDB文档存储一般用类似json的格式存储,存储的内容是文档型的。这样也就有机会对某些字段建立索引,实现关系数据库的某些功能。
对象存储db4o、Versant通过类似面向对象语言的语法操作数据库,通过对象的方式存取数据。
key-value存储Tokyo Cabinet / Tyrant、Berkeley DB、MemcacheDB、Redis可以通过key快速查询到其value。一般来说,存储不管value的格式,照单全收。(Redis包含了其他功能)
图存储Neo4J、FlockDB图形关系的最佳存储。使用传统关系数据库来解决的话性能低下,而且设计使用不方便。
xml数据库Berkeley DB XML 、BaseX高效的存储XML数据,并支持XML的内部查询语法,比如XQuery,Xpath。

数据库

Redis

redis是一个高性能的key-value数据库,是为了解决高并发、高扩展、大数据存储等一系列问题产生的数据库解决方案。Redis本质是一个key-value类型的内存数据库,整个数据库系统加载在内存当中进行操作,定期通过异步操作把数据库数据持久化,因此redis的性能非常出色。另外Redis支持保存多种数据结构,如string、list、set,hash等。Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写。

数据类型

string
  • 常用命令:set/get/decr/incr/mget等
  • 应用场景:普通的key/value存储都可以,string在redis内部默认是一个字符串
Hash
  • 常用命令:hget/hset/hgetall等

  • 应用场景 :我们要存储一个用户信息对象数据,其中包括用户ID、用户姓名、年龄和生日,通过用户ID我们希望获取该用户的姓名或者年龄或者生日;

  • 实现方式:Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口。如图所示,Key是用户ID, value是一个Map。这个Map的key是成员的属性名,value是属性值。这样对数据的修改和存取都可以直接通过其内部Map的Key(Redis里称内部Map的key为field),也就是通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据。当前HashMap的实现有两种方式:当HashMap的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,这时对应的value的redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时redisObject的encoding字段为int。

List
  • 常用命令:lpush/rpush/lpop/rpop/lrange等;
  • 应用场景:Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的;
  • 实现方式:set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。
Sorted Set
  • 常用命令:zadd/zrange/zrem/zcard等;
  • 应用场景:Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构,比如twitter 的public timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。
  • 实现方式:Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。

各种数据类型的应用场景:

类型简介特性场景
string 字符串二进制安全可以包含任何数据,如jpg图像或者序列化对象,一个键最大能存储512M适合多种应用场景
Hash 字典键值对集合,即编程语言中的map类型适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值存储、读取、修改用户属性
List 列表链表,双向链表增删快,提供了某一段元素的API最新消息排行等功能;消息队列
Set 集合哈希表实现,元素不重复1. 添加、删除、查找的复杂度都是O(1);2. 为集合提供了求交集、并集、差集等操作1. 共同好友;2、 利用唯一性,统计访问网站的所有独立ip;3. 好友推荐时,根据tag求交集,大于某个阈值就可以推荐
Sorted Set 有序集合将Set中的元素增加了一个权重参数score,元素按照score有序排序数据插入集合时,已经进行天然排序1. 排行榜;2. 待权重消息队列

Redis应用场景

  1. 会话缓存:如存储token、用户密码等
  2. 消息队列
  3. 排行榜/点赞数等计数器
  4. 发布订阅

缓存失效策略

  1. viliate-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
  2. volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰
  3. volatile-random:从已设置过期时间的数据集中任意选择数据淘汰
  4. allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
  5. allkeys-random:从数据集中任意选择数据淘汰
  6. no-enviction(驱动):禁止驱逐数据

redis事务

在redis中MULTI/EXEC/DISCARD/WATCH这四个命令是实现事务的基石。

  1. 在事务中的所有命令都将会被串行化的顺序执行,事务执行期间,Redis不会再为其它客户端的请求提供任何服务,从而保证了事物中的所有命令被原子的执行。

  2. 和关系型数据库中的事务相比,在Redis事务中如果有某一条命令执行失败,其后的命令仍然会被继续执行。

  3. 我们可以通过MULTI命令开启一个事务,有关系型数据库开发经验的人可以将其理解为"BEGIN TRANSACTION"语句。在该语句之后执行的命令都将被视为事务之内的操作,最后我们可以通过执行EXEC/DISCARD命令来提交/回滚该事务内的所有操作。这两个Redis命令可被视为等同于关系型数据库中的COMMIT/ROLLBACK语句。

  4. 在事务开启之前,如果客户端与服务器之间出现通讯故障并导致网络断开,其后所有待执行的语句都将不会被服务器执行。然而如果网络中断事件是发生在客户端执行EXEC命令之后,那么该事务中的所有命令都会被服务器执行。

  5. 当使用Append-Only模式时,Redis会通过调用系统函数write将该事务内的所有写操作在本次调用中全部写入磁盘。然而如果在写入的过程中出现系统崩溃,如电源故障导致的宕机,那么此时也许只有部分数据被写入到磁盘,而另外一部分数据却已经丢失。Redis服务器会在重新启动时执行一系列必要的一致性检测,一旦发现类似问题,就会立即退出并给出相应的错误提示。此时,我们就要充分利用Redis工具包中提供的redis-check-aof工具,该工具可以帮助我们定位到数据不一致的错误,并将已经写入的部分数据进行回滚。修复之后我们就可以再次重新启动Redis服务器了。

redis持久化

  • RDB:在指定的时间间隔对数据进行快照存储
  • AOF:记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始数据
RDB

在redis中RDB持久化的触发分为两种:手动触发以及Redis定时触发。

  1. 手动触发
    手动触发持久化的操作有两个:savebgsave,区别在于是否阻塞Redis主线程的执行。

  2. 自动触发

    • save m n是指在m秒内,如果有n个键发生改变,则自动触发持久化。
    • flushall用于清空redis数据库,在生产环境下一定慎用。
    • 主从同步触发:在redis主从复制中,当从节点执行全量复制操作时,主节点会执行bgsave命令,并将RDB文件发送给从节点,该过程会自动触发redis持久化。

RDB的优点:RDB 的内容为二进制的数据,占用内存更小,更紧凑,更适合做为备份文件;RDB 对灾难恢复非常有用,它是一个紧凑的文件,可以更快的传输到远程服务器进行 Redis 服务恢复;RDB 可以更大程度的提高 Redis 的运行速度,因为每次持久化时 Redis 主进程都会 fork 一个子进程,进行数据持久化到磁盘,Redis 主进程并不会执行磁盘 I/O 等操作;与后面介绍的 AOF 格式的文件相比,RDB 文件可以更快的重启。缺点:因为 RDB 只能保存某个时间间隔的数据,如果中途 Redis 服务被意外终止了,则会丢失一段时间内的 Redis 数据;RDB 需要经常 fork 才能使用子进程将其持久化在磁盘上。如果数据集很大,fork 可能很耗时,并且如果数据集很大且 CPU 性能不佳,则可能导致在几毫秒甚至一秒钟内 Redis 无法为客户端服务。

AOF

AOF(Append Only File)指的是追加到文件,所以 AOF 我们可以猜测它应该类似于日志文件一样,事实上也确实如此。但它和我们熟悉的数据库的预写式日志(Write Ahead Log,WAL)不同,WAL 是先把修改的数据记到日志文件中,然后执行相关操作;而 AOF 正好相反,Redis 是先执行命令、将数据写入内存,然后才记录日志。
优点: AOF 持久化保存的数据更加完整,AOF 提供了三种保存策略:每次操作保存、每秒钟保存一次、跟随系统的持久化策略保存,其中每秒保存一次,从数据的安全性和性能两方面考虑是一个不错的选择,也是 AOF 默认的策略,即使发生了意外情况,最多只会丢失 1s 钟的数据;AOF 采用的是命令追加的写入方式,所以不会出现文件损坏的问题,即使由于某些意外原因,导致了最后操作的持久化数据写入了一半,也可以通过 redis-check-aof 工具轻松的修复;AOF 持久化文件,非常容易理解和解析,它是把所有 Redis 键值操作命令,以文件的方式存入了磁盘。即使不小心使用 flushall 命令删除了所有键值信息,只要使用 AOF 文件,重启 Redis 即可恢复之前误删的数据,但前提是把 AOF 文件中最后的 flushall 命令删除之后再恢复,否则恢复完之后就又 flushall 了。缺点 对于相同的数据集来说,AOF 文件要大于 RDB 文件;在 Redis 负载比较高的情况下,RDB 比 AOF 性能更好;RDB 使用快照的形式来持久化整个 Redis 数据,而 AOF 只是将每次执行的命令追加到 AOF 文件中,因此从理论上说,RDB 比 AOF 更健壮。

参考:https://www.cnblogs.com/traditional/p/13296648.html

MongoDB

MongoDB 是一款流行的开源文档型数据库,具有高性能、高可用和易于扩展的特性。MongoDB将数据存储为一个文档,数据结构有键值对(key:value)组成。MongoDB文档类似于JSON对象。字段值可以包含其他文档、数组以及文档数据。以下是MongoDB的一些应用案例:

  • Craiglist:使用MongoDB的存档数十亿记录
  • FourSquare:基于位置的社交网络,在Amazon EC2的服务器上使用MongoDB分享数据
  • Shutterfly:以互联网为基础的社会和个人出版服务,使用mongodb的各种持久化数据存储的要求

MongDB安装

  1. 拉取最新的mongodb版本镜像:docker pull mongo:lastest
  2. 由于数据库数据需要持久化,因此需要新建一个挂载mongodb的文件夹,在这里假设成/home/mongodb/data
  3. 启动镜像,执行以下的命令:docker run -p 27017:27017 -v /home/mongodb/data:/data/db --name mongodb -d mongo。此时mongodb可以进行操作了,但是不安全,因为还没有设置账号密码。任何人只要知道你的地址即可访问你的数据库。
  4. 在运行的镜像中,进入到容器的bin/bash环境,执行mongo admin进入mongodb,然后执行以下语句创建用户:
    db.createUser({
    user: 'admin',
    pwd: 'Aa123456',
    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
    });
    
  5. 重新运行容器:docker run -p 27017:27017 -v /home/mongodb/data:/data/db --name mongodb -d mongo` --auth
    在这里插入图片描述
    在这里不推荐使用docker安装mongodb。

可视化界面工具

这里使用MongoDB Compass作为可视化界面工具。

在这里插入图片描述

概念解析

关系型数据库概念MongoDB概念说明
databasedatabase数据库
tablecollection数据库表/集合
rowdocument数据库记录行/文档
columnfield数据字段/域
indexindex索引

用户角色

用户角色权限
Read允许用户读取指定数据库
readWrite允许用户读写指定数据库
dbAdmin允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile
userAdmin允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户
clusterAdmin只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。
readAnyDatabase只在admin数据库中可用,赋予用户所有数据库的读权限
readWriteAnyDatabase只在admin数据库中可用,赋予用户所有数据库的读写权限
userAdminAnyDatabase只在admin数据库中可用,赋予用户所有数据库的userAdmin权限
dbAdminAnyDatabase只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。
root只在admin数据库中可用。超级账号,超级权限。

相关教程

  1. mongodb官网
  2. 菜鸟教程

HBase

关于HBase,我接触不多,以下内容摘抄自HBase 百度百科。HBase是一个分布式的、面向列的开源数据库。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。另一个不同的是HBase基于列的而不是基于行的模式。

Neo4j

Neo4j是一个高性能的,NOSQL图形数据库,它将结构化数据存储在网络上而不是表中。它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络(从数学角度叫做图)上而不是表中。Neo4j也可以被看作是一个高性能的图引擎,该引擎具有成熟数据库的所有特性。程序员工作在一个面向对象的、灵活的网络结构下而不是严格、静态的表中——但是他们可以享受到具备完全的事务特性、企业级的数据库的所有好处。Neo4j因其嵌入式、高性能、轻量级等优势,越来越受到关注。

Python实现

我已经用mongodb以及redis去模拟一个登录过程,详情可以参考我的repo:Flask-HTTPAuth

Redis

Redis的操作主要列出一些比较常用的命令代码以及对应的功能。

连接redis

import redis
r = redis.Redis(host=localhost, port=port, password=password, db='1')
r.set('name', 'pd')
val = r.get('name')
print(val)
r.close()

'''
连接池的方式链接
好处:使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。
'''
pool = redis.ConnectionPool(host=localhost, port=port, password=password, max_connections=1000)
r = redis.Redis(connection_pool=pool)
r.set('test', 'test')

在上述代码中涉及r.set(),里面涉及到以下的参数:

  • ex:设置过期时间(秒),r.set('food', 'mutton', ex=3)
  • px:设置过期时间毫秒,r.set('food', 'beef', px=3)
  • nx:如果为True,则只有name不存在时,当前set操作才执行,r.set('fruit', 'watermelon', nx=True)
  • xx:如果为True,则只有name存在时,当前set操作才执行,r.set('fruit', 'watermelon', xx=True)

具体的操作可以参考官网的api。

MongoDB

以一个用户信息为例:

# mongodb操作类
import pymongo

class MongoClient():
    def __init__(self, host, port, *args, **kwargs):
        self._mongo = pymongo.MongoClient(host=host, port=port, password=kwargs['password'], username=kwargs['username'])
    
    def database(self, database):
        db= self._mongo[database]
        return db

    def close(self):
        self._mongo.close()
from .mongodb import MongoClient
from bson import ObjectId

def regist(userinfo):
    try:
        client = MongoClient(config.MONGODB_HOST, int(config.MONGODB_PORT), username = config.MONGODB_USER, password= config.MONGODB_PASSWORD)
        db = client.database('test')
        result = db['user'].insert_one(userinfo)
        return str(result.inserted_id)
    except Exception as e:
        raise e
    finally:
        client.close()

def updateuser(condition, userinfo):
    try:
        client = MongoClient(config.MONGODB_HOST, int(config.MONGODB_PORT), username = config.MONGODB_USER, password= config.MONGODB_PASSWORD)
        db = client.database('test')
        result = db['user'].update_one(condition, {'$set':userinfo})
        return result
    except Exception as e:
        raise e
    finally:
        client.close()

def deleteUser(objectid):
    try:
        condition={}
        condition['_id'] = ObjectId(objectid)
        client = MongoClient(config.MONGODB_HOST, int(config.MONGODB_PORT), username = config.MONGODB_USER, password= config.MONGODB_PASSWORD)
        db = client.database('test')
        result = db['user'].delete_one(condition)
        return result
    except Exception as e:
        raise e
    finally:
        client.close()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值