缓存数据库介绍
NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”,泛指非关系型的数据库,随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,
特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。
NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题。
NoSQL数据库的四大分类:
这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特定的数据。Key/value模型对于IT系统来说的优势在于简单、易部署。
但是如果DBA只对部分值进行查询或更新的时候,Key/value就显得效率低下了。[3] 举例如:Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB.
列存储数据库:
这部分数据库通常是用来应对分布式存储的海量数据。键仍然存在,但是它们的特点是指向了多个列。这些列是由列家族来安排的。如:Cassandra, HBase, Riak.
文档型数据库:
文档型数据库的灵感是来自于Lotus Notes办公软件的,而且它同第一种键值存储相类似。该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如JSON。
文档型数据库可 以看作是键值数据库的升级版,允许之间嵌套键值。而且文档型数据库比键值数据库的查询效率更高。如:CouchDB, MongoDb. 国内也有文档型数据库SequoiaDB,已经开源。
图形(Graph)数据库:
NoSQL数据库的四大分类表格分析:
redis
介绍:
redis是业界主流的key-value nosql 数据库之一。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、
zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。
在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,
数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis优点:
-
异常快速 : Redis是非常快的,每秒可以执行大约110000设置操作,81000个/每秒的读取操作。
-
支持丰富的数据类型 : Redis支持最大多数开发人员已经知道如列表,集合,可排序集合,哈希等数据类型。
这使得在应用中很容易解决的各种问题,因为我们知道哪些问题处理使用哪种数据类型更好解决。 -
操作都是原子的 : 所有 Redis 的操作都是原子,从而确保当两个客户同时访问 Redis 服务器得到的是更新后的值(最新值)。
-
MultiUtility工具:Redis是一个多功能实用工具,可以在很多如:缓存,消息传递队列中使用(Redis原生支持发布/订阅),在应用程序中,如:Web应用程序会话,网站页面点击数等任何短暂的数据;
安装Redis环境:
$sudo apt-get update
$sudo apt-get install redis-server
启动 Redis
$redis-server
查看 redis 是否还在运行
$redis-cli
redis 127.0.0.1:6379>
redis 127.0.0.1:6379> ping
PONG
sudo pip install redis
or
sudo easy_install redis
or
源码安装
详见:https:
/
/
github.com
/
WoLpH
/
redis
-
py
连接方式
1、操作模式
redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,
Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。
import redis
r = redis.Redis(host='localhost', port=6379)
r.set('foo', 'Bar')
print r.get('foo')
2、连接池
redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。
可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池。
连接池code:
#Author:Yun
import redis
pool = redis.ConnectionPool(host='localhost',port = 6379)
r = redis.Redis(connection_pool=pool)
r.set('foo2','Bar2')
print(r.get('foo2'))
操作
1. String操作
set(name, value, ex=None, px=None, nx=False, xx=False)
在Redis中设置值,默认,不存在则创建,存在则修改
参数:
ex,过期时间(秒)
px,过期时间(毫秒)
nx,如果设置为True,则只有name不存在时,当前set操作才执行
xx,如果设置为True,则只有name存在时,岗前set操作才执行
127.0.0.1:6379> set name luban
OK
127.0.0.1:6379> set age 22
OK
127.0.0.1:6379> keys * #获取所有的key
1) "age" 2) "name"
127.0.0.1:6379> set name hehe ex 2#ex 2是指只存活两秒钟
OK
127.0.0.1:6379> get name
(nil)
setnx(name, value)
设置值,只有name不存在时,执行设置操作(添加)
get(name)
获取值
127.0.0.1:6379> get name
"luban" 127.0.0.1:6379> get age "22"
setex(name, value, time)
设置值
参数:
time,过期时间(数字秒 或 timedelta对象)
mget(keys, *args)
批量获取
127.0.0.1:6379> mget n1 n2#批量获取Value
1) "1"
2) "2"
getset(name, value)
1 设置新值并获取原来的值
127.0.0.1:6379> set n3 3
OK
127.0.0.1:6379> get n3
"3"
127.0.0.1:6379> getset n3 hehe#设置新值并获取原来的值
"3"
getrange(key, start, end)
获取子序列(根据字节获取,非字符)
# 参数:
# name,Redis 的 name
# start,起始位置(字节)
# end,结束位置(字节)
# 如: "武沛齐" ,0-3表示 "武"
127.0.0.1:6379> set n1 luban
OK
127.0.0.1:6379> getrange n1 0 2#切片
"lub"
setrange(name, offset, value)
修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
# 参数:
# offset,字符串的索引,字节(一个汉字三个字节)
# value,要设置的值
127.0.0.1:6379> set n2 houyi
OK
127.0.0.1:6379> setrange n2 1 ee#替换
(integer) 5
127.0.0.1:6379> get n2
"heeyi"
# 对name对应值的二进制表示的位进行操作
# 参数:
# name,redis的name
# offset,位的索引(将值变换成二进制后再进行索引)
# value,值只能是 1 或 0
# 注:如果在Redis中有一个对应: n1 = "foo",
那么字符串foo的二进制表示为:01100110 01101111 01101111
所以,如果执行 setbit('n1', 7, 1),则就会将第7位设置为1,
那么最终二进制则变成 01100111 01101111 01101111,即:"goo"
# 扩展,转换二进制表示:
# source = "鲁班大师"
source = "foo"
for i in source:
num = ord(i)
print(bin(num).replace('b',''))
特别的,如果source是汉字 "鲁班"怎么办?
>>> ord('鲁')
40065
>>> bin(40065)
'0b1001110010000001'
>>>
答:对于utf-8,每一个汉字占 3 个字节,那么 "鲁班" 则有 6个字节
对于汉字,for循环时候会按照 字节 迭代,那么在迭代时,将每一个字节转换 十进制数,然后再将十进制数转换成二进制
------------------------鲁班--------------------------------------------------------
00000000 10011100 10000001 00000000 01110011 11101101
应用场景:
*用途举例,用最省空间的方式,存储在线用户数及分别是哪些用户在线
setbit n5 100 1#设置用户登录状态位,n5是用户名,100是用户id
127.0.0.1:6379> setbit bb 1000 1#来一个用户标记一下
(integer) 0
127.0.0.1:6379> setbit bb 100 1#来一个在标记一个
(integer) 0
127.0.0.1:6379> setbit bb 230 1
(integer) 0
获取name对应的值的二进制表示中的某位的值 (0或1)
应用场景:
getbit n5 100 #检测用户登录状态位,是否在线,1-在线;0-不在线
127.0.0.1:6379> getbit bb 230#检测用户230 是否在线
(integer) 1 #在线
127.0.0.1:6379> getbit bb 233#检测用户233是否在线
(integer) 0 #不在线
127.0.0.1:6379>
应用:可以将10亿用户的的登陆状态和在线人数存储到10MB空间中去
bitcount(key, start=None, end=None)
获取name对应的值的二进制表示中 1 的个数
# 参数:
# key,Redis的name
# start,位起始位置
# end,位结束位置
127.0.0.1:6379> bitcount bb#统计上线用户数量
(integer) 3
strlen(name)
返回name对应值的字节长度(一个汉字3个字节)
127.0.0.1:6379> set hh '你好'
OK
127.0.0.1:6379> strlen hh
(integer) 6
127.0.0.1:6379>
incr(self, name, amount=1)
自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
参数:
name,Redis的name
amount,自增数(必须是整数)
127.0.0.1:6379> incr login_users#统计在线计数器
(integer) 1
127.0.0.1:6379> incr login_users
(integer) 2
127.0.0.1:6379> incr login_users
(integer) 3
127.0.0.1:6379> incr login_users
(integer) 4
127.0.0.1:6379> incr login_users
(integer) 5
127.0.0.1:6379> decr login_users
(integer) 4
127.0.0.1:6379> decr login_users
(integer) 3
127.0.0.1:6379>
incrbyfloat(self, name, amount=1.0)
自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
参数:
name,Redis的name
amount,自增数(浮点型)
127.0.0.1:6379> INCRBYFLOAT 2 1.2
"1.2"
127.0.0.1:6379> INCRBYFLOAT 2 1.2
"2.4"
127.0.0.1:6379> INCRBYFLOAT 2 1.2
"3.6"
# 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
# 参数:
# name,Redis的name
# amount,自减数(整数)
# 在redis name对应的值后面追加内容
# 参数:
key, redis的name
value, 要追加的字符串
127.0.0.1:6379> set s1 sea
OK
127.0.0.1:6379> append s1 blue
(integer) 7
127.0.0.1:6379> get s1
"seablue"
127.0.0.1:6379>
2. Hash操作
hash表现形式上有些像pyhton中的dict,可以存储一组关联性较强的数据 , redis中Hash在内存中的存储格式如下图:
hset(name, key, value)
# name对应的hash中设置一个键值对(不存在,则创建;否则,修改)
# 参数:
# name,redis的name
# key,name对应的hash中的key
# value,name对应的hash中的value
# 注:
# hsetnx(name, key, value),当name对应的hash中不存在当前key时则创建(相当于添加)
127.0.0.1:6379> hset info name luban
(integer) 1
127.0.0.1:6379> hset info age 22
(integer) 1
127.0.0.1:6379> hset info id 8848
(integer) 1
127.0.0.1:6379> hgetall info#获取info下的所有key-value
1) "name"
2) "luban"
3) "age"
4) "22"
5) "id"
6) "8848"
# 在name对应的hash中批量设置键值对
# 参数:
# name,redis的name
# mapping,字典,如:{'k1':'v1', 'k2': 'v2'}
# 如:
# r.hmset('xx', {'k1':'v1', 'k2': 'v2'})
127.0.0.1:6379> hmset info2 k1 2 k2 3#批量设置
OK
127.0.0.1:6379> hkeys info2
1) "k1"
2) "k2"
# 在name对应的hash中获取根据key获取value
# 在name对应的hash中获取多个key的值
# 参数:
# name,reids对应的name
# keys,要获取key集合,如:['k1', 'k2', 'k3']
# *args,要获取的key,如:k1,k2,k3
# 如:
# r.mget('xx', ['k1', 'k2'])
# 或
# print r.hmget('xx', 'k1', 'k2')
127.0.0.1:6379> hmget info3 n1 n2
1) "1"
2) "2"
获取name对应hash的所有键值对
127.0.0.1:6379> hgetall info2
1) "k1"
2) "2"
3) "k2"
4) "3"
# 获取name对应的hash中键值对的个数
127.0.0.1:6379> hlen info2#获取info2中有几个key
(integer) 2
获取name对应的hash中所有的key的值
127.0.0.1:6379> hkeys info2
1) "k1"
2) "k2"
# 获取name对应的hash中所有的value的值
127.0.0.1:6379> hvals info#获取info下的所有value
1) "luban"
2) "22"
3) "8848"
# 检查name对应的hash是否存在当前传入的key
127.0.0.1:6379> hexists info2 k1#检查info2下的k1这个key是否存在,存在返回1,否则0
(integer) 1
127.0.0.1:6379> hexists info2 k3
(integer) 0
# 将name对应的hash中指定key的键值对删除
127.0.0.1:6379> hdel info2 k2#删除info2下的k2及其value
(integer) 1
127.0.0.1:6379> hget info2 k2
(nil)
# 自增name对应的hash中的指定key的值,不存在则创建key=amount
# 参数:
# name,redis中的name
# key, hash对应的key
# amount,自增数(整数)
127.0.0.1:6379> hincrby info2 k2 1#自增name对应的hash中指定key的值,不存在则创建,value=amount
(integer) 1
127.0.0.1:6379> hincrby info2 k2 1
(integer) 2
127.0.0.1:6379> hincrby info2 k2 1
(integer) 3
127.0.0.1:6379> hincrby info2 k2 1
(integer) 4
127.0.0.1:6379> hincrby info2 k2 1
(integer) 5
# 自增name对应的hash中的指定key的值,不存在则创建key=amount
# 参数:
# name,redis中的name
# key, hash对应的key
# amount,自增数(浮点数)
# 自增name对应的hash中的指定key的值,不存在则创建key=amount
127.0.0.1:6379> HINCRBYFLOAT info5 n2 1.2
"1.2"
127.0.0.1:6379> HINCRBYFLOAT info5 n2 1.2
"2.4"
127.0.0.1:6379> HINCRBYFLOAT info5 n2 1.2
"3.6"
127.0.0.1:6379> hget info5 n2
"3.6"
127.0.0.1:6379>
使用以下命令启动完整哈希扫描 HSCAN myhash 0 使用与模式匹配的字段开始哈希扫描: HSCAN myhash 0 MATCH order_* 使用与模式匹配的字段启动哈希扫描,并强制扫描命令执行更多操作 扫描: HSCAN myhash 0 MATCH order_* COUNT 1000 # 增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,导致内存被撑爆,而是分片的获取数据 # 参数: # name,redis的name # cursor,游标(基于游标分批去获取数据) # match,匹配指定key,默认None 表示所有的key # count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数 # 如: # 第一次:cursor1, data1 = r.hscan('xx', cursor=0, match=None, count=None) # 第二次:cursor2, data1 = r.hscan('xx', cursor=cursor1, match=None, count=None) # ... # 直到返回值cursor的值为0时,表示数据已经通过分片获取完毕 127.0.0.1:6379> HSCAN info 0
1) "0"
2) 1) "name"
2) "luban"
3) "age"
4) "22"
5) "id"
6) "8848"
127.0.0.1:6379> hscan info2 0 match k*#过滤以k开头的key 1) "0" 2) 1) "k1" 2) "2" 3) "k2" 4) "6" 127.0.0.1:6379>
# 利用yield封装hscan创建生成器,实现分批去redis中获取数据
# 参数:
# match,匹配指定key,默认None 表示所有的key
# count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
# 如:
# for item in r.hscan_iter('xx'):
# print(item)
# 在name对应的list中添加元素,每个新的元素都添加到列表的最左边
# 如:
# r.lpush('oo', 11,22,33)
# 保存顺序为: 33,22,11
# 扩展:
# rpush(name, values) 表示从右向左操作
127.0.0.1:6379> lpush names luban houyi daji#先入后出创建列表
(integer) 3
# 在name对应的列表分片获取数据
# 参数:
# name,redis的name
# start,索引的起始位置
# end,索引结束位置
127.0.0.1:6379> lrange names 0 -1
1) "daji"
2) "houyi"
3) "luban"
#在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边
# 更多:
# rpushx(name, value) 表示从右向左操作
127.0.0.1:6379> lpushx l5 hehe
(integer) 0
127.0.0.1:6379> lrange l5 0 -1
(empty list or set)
127.0.0.1:6379> lpush L5 1 2 3 4
(integer) 4
127.0.0.1:6379> lrange L5 0 -1
1) "4"
2) "3"
3) "2"
4) "1"
127.0.0.1:6379> lpushx L5 hehe
(integer) 5
127.0.0.1:6379> lrange L5 0 -1
1) "hehe"
2) "4"
3) "3"
4) "2"
5) "1"
127.0.0.1:6379>
# name对应的list元素的个数
127.0.0.1:6379> lrange L5 0 -1
1) "hehe"
2) "4"
3) "3"
4) "2"
5) "1"
127.0.0.1:6379> llen L5
(integer) 5
# 在name对应的列表的某一个值前或后插入一个新值
# 参数:
# name,redis的name
# where,BEFORE或AFTER
# refvalue,标杆值,即:在它前后插入数据
# value,要插入的数据
127.0.0.1:6379> linsert names before luban houzi#在luban 前面插入数据
(integer) 6
127.0.0.1:6379> lrange names 0 -1
1) "daji"
2) "houyi"
3) "houzi"
4) "luban"
5) "hanxin"
6) "laofuzi"
127.0.0.1:6379> linsert names after luban kai#在luban 后面插入数据
(integer) 7
127.0.0.1:6379> lrange names 0 -1
1) "daji"
2) "houyi"
3) "houzi"
4) "luban"
5) "kai"
6) "hanxin"
7) "laofuzi"
# 对name对应的list中的某一个索引位置重新赋值
# 参数:
# name,redis的name
# index,list的索引位置
# value,要设置的值
127.0.0.1:6379> lrange names 0 -1
1) "daji"
2) "houyi"
3) "houzi"
4) "luban"
5) "kai"
6) "hanxin"
7) "laofuzi"
127.0.0.1:6379> lset names 3 LuBan#重新给names列表中 索引为3的位置赋值
OK
127.0.0.1:6379> lrange names 0 -1
1) "daji"
2) "houyi"
3) "houzi"
4) "LuBan"
5) "kai"
6) "hanxin"
7) "laofuzi"
# 在name对应的list中删除指定的值
# 参数:
# name,redis的name
# value,要删除的值
# num, num=0,删除列表中所有的指定值;
# num=2,从前到后,删除2个;
# num=-2,从后向前,删除2个
127.0.0.1:6379> lrem names 1 houzi #删除指定的值
(integer) 1
127.0.0.1:6379> lrange names 0 -1
1) "daji"
2) "houyi"
3) "LuBan"
4) "kai"
5) "hanxin"
6) "laofuzi"
# 在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素
# 更多:
# rpop(name) 表示从右向左操作
127.0.0.1:6379> lpop names#从列表最左边取出一个元素删除,类似于队列
"daji"
127.0.0.1:6379> lrange names 0 -1
1) "houyi"
2) "LuBan"
3) "kai"
4) "hanxin"
5) "laofuzi"
127.0.0.1:6379>
在name对应的列表中根据索引获取列表元素
127.0.0.1:6379> lindex L5 1
"4"
127.0.0.1:6379> lindex L5 0
"hehe"
127.0.0.1:6379> lindex L5 2
"3"
127.0.0.1:6379>
# 在name对应的列表中移除没有在start-end索引之间的值
# 参数:
# name,redis的name
# start,索引的起始位置
# end,索引结束位置
127.0.0.1:6379> lrange names 0 -1
1) "houyi"
2) "LuBan"
3) "kai"
4) "hanxin"
5) "laofuzi"
127.0.0.1:6379> ltrim names 1 2#只保留列表names 索引为 1 -2 的元素
OK
127.0.0.1:6379> lrange names 0 -1
1) "LuBan"
2) "kai"
# 从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边
# 参数:
# src,要取数据的列表的name
# dst,要添加数据的列表的name
127.0.0.1:6379> lrange names 0 -1
1) "LuBan"
2) "kai"
127.0.0.1:6379> lrange names2 0 -1
1) "hehe"
127.0.0.1:6379> rpoplpush names names2#移除names最右边的元素,同时添加到names2的最左边
"kai"
127.0.0.1:6379> lrange names2 0 -1
1) "kai"
2) "hehe"
127.0.0.1:6379> lrange names 0 -1
1) "LuBan"
# 将多个列表排列,按照从左到右去pop对应列表的元素
# 参数:
# keys,redis的name的集合
# timeout,超时时间,当元素所有列表的元素获取完之后,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞
# 更多:
# r.brpop(keys, timeout),从右向左获取数据
# 从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧 # 参数: # src,取出并要移除元素的列表对应的name # dst,要插入元素的列表对应的name # timeout,当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞
127.0.0.1:6379> brpoplpush names names2 40
#从列表names的最右端移除一个元素并添加到另一个列表names2的左侧
#当列表中没有数据阻塞等待40s
"hehhe"
(12.69s)
127.0.0.1:6379> lrange names2 0 -1
1) "hehhe"
2) "LuBan"
3) "kai"
4) "hehe"
应用场景:
两个进程,一个进程放数据,另一个进程取数据;
保证数据一致性,同步放数据,同步取数据并删除,双方不影响
# name对应的集合中添加元素
127.0.0.1:6379> sadd names3 luban luban hehe hehe 2323#集合天生去重
(integer) 3
# 获取name对应的集合的所有成员
127.0.0.1:6379> smembers names3
1) "2323"
2) "luban"
3) "hehe
获取name对应的集合中元素个数
127.0.0.1:6379> scard names3#获取names3集合中的元素个数
(integer) 3
在第一个name对应的集合中且不在其他name对应的集合的元素集合
127.0.0.1:6379> sadd names4 hanxin houzi kai 2323 hehe
127.0.0.1:6379> sdiff names3 names4#返回names3有的而names4中没有的元素
1) "luban"
sdiffstore(dest, keys, *args)
# 获取第一个name对应的集合中且不在其他name对应的集合,再将其新加入到dest对应的集合中
127.0.0.1:6379> sdiffstore n5 names3 names4
#将names3有的而names4中没有的元素重新加入到集合n5中
(integer) 1
127.0.0.1:6379> smembers n5
1) "luban"
# 获取多一个name对应集合的交集
127.0.0.1:6379> sinter names3 names4#返回呢两个集合的交集
1) "2323"
2) "hehe"
# 获取多一个name对应集合的交集,再讲其加入到dest对应的集合中
127.0.0.1:6379> SINTERSTORE names34 names3 names4
(integer) 2
127.0.0.1:6379> SMEMBERS names34
1) "hehe"
2) "2323"
# 检查value是否是name对应的集合的成员
127.0.0.1:6379> SISMEMBER names34 'hehe'#是返回1
(integer) 1
127.0.0.1:6379> SISMEMBER names34 123#不是返回0
(integer) 0
# 将某个成员从一个集合中移动到另外一个集合
127.0.0.1:6379> sadd s2 1 2 3
(integer) 3
127.0.0.1:6379> sadd s3 4 5 6
(integer) 3
127.0.0.1:6379> SMOVE s2 s3 1
(integer) 1
127.0.0.1:6379> smembers s2
1) "2"
2) "3"
127.0.0.1:6379> smembers s3
# 从集合的右侧(尾部)移除一个成员,并将其返回
127.0.0.1:6379> smembers s3
1) "1"
2) "4"
3) "5"
4) "6"
127.0.0.1:6379> spop s3
"6"
# 从name对应的集合中随机获取 numbers 个元素
127.0.0.1:6379> SRANDMEMBER s3 2
1) "5"
2) "4"
127.0.0.1:6379> SRANDMEMBER s3 2
1) "1"
2) "4"
127.0.0.1:6379> SRANDMEMBER s3 2
1) "5"
2) "4"
# 在name对应的集合中删除某些值
127.0.0.1:6379> smembers s3
1) "1"
2) "4"
3) "5"
127.0.0.1:6379> srem s3 1#删除s3集合中的成员1
(integer) 1
127.0.0.1:6379> smembers s3
1) "4"
2) "5"
# 获取多个或一个name对应的集合的并集
127.0.0.1:6379> sunion s2
1) "2"
2) "3"
127.0.0.1:6379> sunion s2 s3
1) "2"
2) "3"
3) "4"
4) "5"
# 获取多一个name对应的集合的并集,并将结果保存到dest对应的集合中
127.0.0.1:6379> sunionstore s23_union s2 s3
(integer) 4
127.0.0.1:6379> smembers s23_union
1) "2"
2) "3"
3) "4"
4) "5"
sscan_iter(name, match=None, count=None)
# 在name对应的有序集合中添加元素
# 如:
# zadd('zz', 'n1', 1, 'n2', 2)
# 或
# zadd('zz', n1=11, n2=22)
127.0.0.1:6379> zadd z1 10 he 3 hehe 6 hehe
(integer) 2
127.0.0.1:6379> zadd z1 10 he 3 hehe 6 hehehe
(integer) 1
127.0.0.1:6379> ZRANGE z1 0 -1 withscores
1) "hehe"
2) "3"
3) "hehehe"
4) "6"
5) "he"
6) "10"
# 按照索引范围获取name对应的有序集合的元素
# 参数:
# name,redis的name
# start,有序集合索引起始位置(非分数)
# end,有序集合索引结束位置(非分数)
# desc,排序规则,默认按照分数从小到大排序
# withscores,是否获取元素的分数,默认只获取元素的值
# score_cast_func,对分数进行数据转换的函数
# 更多:
# 从大到小排序
# zrevrange(name, start, end, withscores=False, score_cast_func=float)
# 按照分数范围获取name对应的有序集合的元素
# zrangebyscore(name, min, max, start=None, num=None, withscores=False, score_cast_func=float)
# 从大到小排序
# zrevrangebyscore(name, max, min, start=None, num=None, withscores=False, score_cast_func=float)
# 获取name对应的有序集合元素的数量
127.0.0.1:6379> ZRANGE z1 0 -1 withscores
1) "daji"
2) "3"
3) "hehe"
4) "3"
5) "houyi"
6) "7"
7) "luban"
8) "10"
127.0.0.1:6379> zcard z1
(integer) 4
# 获取name对应的有序集合中分数 在 [min,max] 之间的个数
127.0.0.1:6379> ZRANGE z1 0 -1 withscores
1) "daji"
2) "3"
3) "hehe"
4) "3"
5) "houyi"
6) "7"
7) "luban"
8) "10"
127.0.0.1:6379> zcount z1 3 4
(integer) 2
# 自增name对应的有序集合的 name 对应的分数
127.0.0.1:6379> zincrby z3 3 num
"3"
127.0.0.1:6379> zincrby z3 3 num
"6"
127.0.0.1:6379> zincrby z3 3 num
"9"
127.0.0.1:6379> zincrby z3 3 num
"12"
127.0.0.1:6379> zrange z3 0 -1 withscores
1) "hehe"
2) "6"
3) "daji"
4) "8"
5) "num"
6) "12"
# 获取某个值在 name对应的有序集合中的排行(从 0 开始)
# 更多:
# zrevrank(name, value),从大到小排序
127.0.0.1:6379> zrange z3 0 -1 withscores
1) "hehe"
2) "6"
3) "daji"
4) "8"
5) "num"
6) "12"
127.0.0.1:6379> zrank z3 daji
(integer) 1
# 删除name对应的有序集合中值是values的成员
# 如:zrem('zz', ['s1', 's2'])
127.0.0.1:6379> zrem z3 'daji'
(integer) 1
127.0.0.1:6379> zrange z3 0 -1 withscores
1) "hehe"
2) "6"
3) "num"
4) "12"
# 根据排行范围删除
127.0.0.1:6379> zrange z1 0 -1 withscores
1) "daji"
2) "3"
3) "hehe"
4) "3"
5) "houyi"
6) "7"
7) "luban"
8) "10"
127.0.0.1:6379> zremrangebyrank z1 0 1
(integer) 2
127.0.0.1:6379> zrange z1 0 -1 withscores
1) "houyi"
2) "7"
3) "luban"
4) "10"
# 根据分数范围删除
127.0.0.1:6379> zrange z4 0 -1 withscores
1) "luban"
2) "2"
3) "wangzhaojun"
4) "3"
5) "daji"
6) "6"
7) "diaochan"
8) "9"
9) "zhenji"
10) "10"
127.0.0.1:6379> zremrangebyscore z4 3 6#删除成绩在[3,6]
(integer) 2
127.0.0.1:6379> zrange z4 0 -1 withscores
1) "luban"
2) "2"
3) "diaochan"
4) "9"
5) "zhenji"
6) "10"
# 获取name对应有序集合中 value 对应的分数
127.0.0.1:6379> zrange z4 0 -1 withscores
1) "luban"
2) "2"
3) "diaochan"
4) "9"
5) "zhenji"
6) "10"
127.0.0.1:6379> zscore z4 'zhenji'
"10"
# 获取两个有序集合的交集,如果遇到相同值,则按照aggregate进行操作
# aggregate的值为: SUM MIN MAX
127.0.0.1:6379> zadd z5 3 luban
(integer) 1
127.0.0.1:6379> zrange z5 0 -1 withscores
1) "luban"
2) "3"
127.0.0.1:6379> zrange z4 0 -1 withscores
1) "luban"
2) "2"
3) "diaochan"
4) "9"
5) "zhenji"
6) "10"
127.0.0.1:6379> zinterstore z45_sum 2 z4 z5
(integer) 1
127.0.0.1:6379> zrange z45_sum 0 -1 withscores
1) "luban"
2) "5"
# 获取两个有序集合的并集,如果遇到相同值不同分数,则按照aggregate进行操作
# aggregate的值为: SUM MIN MAX
127.0.0.1:6379> zrange z6 0 -1 withscores
1) "luban"
2) "2"
127.0.0.1:6379> zrange z4 0 -1 withscores
1) "luban"
2) "2"
3) "diaochan"
4) "9"
5) "zhenji"
6) "10"
127.0.0.1:6379> zunionstore z46_union 2 z4 z6
(integer) 3
127.0.0.1:6379> zrange z46_union 0 -1 withscores
1) "luban"
2) "4"
3) "diaochan"
4) "9"
5) "zhenji"
6) "10"
zscan_iter(name, match=None, count=None,score_cast_func=float)
redis 默认有16个db 0-15,select 5切换db
# 检测redis的name是否存在
# 根据模型获取redis的name
# 更多:
# KEYS * 匹配数据库中所有 key 。
# KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
# KEYS h*llo 匹配 hllo 和 heeeeello 等。
# KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo
# 为某个redis的某个name设置超时时间
# 对redis的name重命名为
# 将redis的某个值移动到指定的db下
# 随机获取一个redis的name(不删除)
# 获取name对应值的类型
scan_iter(match=None, count=None)
# 同字符串操作,用于增量迭代获取key
管道
不使用管道:
import redis from time import time pool = redis.ConnectionPool(db=2,) r = redis.Redis(connection_pool=pool,) start_time = time() for i in range(100000): r.set('{}'.format(i), '{}'.format(i)) end_time = time() print('读写10W条数据,共耗时(ms):', (end_time-start_time)*1000)
使用管道:
import redis from time import time pool = redis.ConnectionPool(host='localhost', port=6379, db=4,) r = redis.Redis( connection_pool=pool,) pipe = r.pipeline(transaction=True) start_time = time() pipe.multi() for i in range(100000): pipe.set(i, i) pipe.execute() end_time = time() print('读写10W条数据,共耗时(ms):', (end_time-start_time)*1000)
发布订阅
发布者:服务器
订阅者:Dashboad和数据处理
Demo如下:
#Author:Yun import redis class RedisHelper: def __init__(self): self.__conn = redis.Redis(host='localhost',port=6379,db=0) self.chan_sub = 'fm104.5' self.chan_pub = 'fm104.5' def public(self, msg): self.__conn.publish(self.chan_pub, msg) return True def subscribe(self): pub = self.__conn.pubsub()#打开收音机 pub.subscribe(self.chan_sub)#调频 pub.parse_response()#准备接收 return pub
#发布方
from redishelper import RedisHelper
obj = RedisHelper()
obj.public('hello')
'''
命令行发布:
PUBLISH fm104.5 hello
'''
#订阅方
from redishelper import RedisHelper
obj = RedisHelper()
redis_sub = obj.subscribe()
while True:
msg = redis_sub.parse_response()
print(msg)
什么时候用关系型数据库,什么时候 用NoSQL?
在以下情况下转到遗留关系数据库(RDBMS):
1、数据结构良好,适用于关系数据库中的表格排列(行和列)。典型示例:银行帐户信息,客户订单信息,客户信息,员工信息,部门信息等。
2、上述观点的另一方面是:面向模式的数据模型。当您为潜在使用RDBMS设计数据模型(表,关系等)时,您需要提出一个定义良好的模式:将有这么多表,
3、非常重要:考虑数据是否具有事务性质。换句话说,是否将在提供ACID语义的事务的上下文中存储,访问和更新数据,或者是否可以妥协某些/所有这些属性。
4、正确性也很重要,任何妥协都是不可接受的。这源于这样一个事实:在大多数NoSQL数据库中,一致性被用于支持性能和可伸缩性(NoSQL数据库上的要点将在下面详述)。
5、对于横向扩展架构没有强烈/迫切的需求;数据库,线性扩展(水平扩展)到群集中的多个节点。
6、用例不适用于“高速数据摄取”。
7、 如果客户端应用程序期望快速地将大量数据流入/流出数据库,那么关系数据库可能不是一个好的选择,因为它们并非真正用于扩展写入繁重的工作负载。
8、为了实现ACID属性,特别是在编写器(INSERT,UPDATE,DELETE)代码路径中进行了大量额外的后台工作。这肯定会影响性能。
9、用例不是“存储数PB范围内的大量数据”。
在以下情况下访问NoSQL数据库:
1、数据不适用于固定(和预定)架构:
2、可扩展性,性能(高吞吐量和低操作延迟),连续可用性是数据库底层架构必须满足的非常重要的要求。
3、 “高速数据摄取”的不错选择。 这样的应用程序(例如IoT样式)在一秒钟内产生数百万个数据点,并且需要能够提供极端写入可伸缩性的数据库。
4、横向扩展的固有能力允许在群集中的商用服务器上存储大量数据。 它们通常使用低成本资源,并且能够随着需求的增长线性增加计算和存储能力。
Django配置Redis
安装
django项目中配置redis作为cache缓存,需要先安装django-redis模块
pip install django-redis
配置
在settings.py中,按如下配置CACHE连接的redis信息:
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 100},
# "PASSWORD": "密码",
"DECODE_RESPONSES":True
}
},
}
使用
先获取redis连接:
import django_redis
CACHE = django_redis.get_redis_connection()
在视图中
...
CACHE.set(key, value)
...