python操作redis

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
简介:

非关系型数据库和关系型数据库的差别:

非关系型数据库的优势:

1. 性能NOSQL是基于键值对的,可以想象成表中的主键和值的对应关系,而且不需要经过SQL层的解析,所以性能非常高。

2. 可扩展性同样也是因为基于键值对,数据之间没有耦合性,所以非常容易水平扩展。

关系型数据库的优势:

1. 复杂查询可以用SQL语句方便的在一个表以及多个表之间做非常复杂的数据查询。

2. 事务支持使得对于安全性能很高的数据访问要求得以实现。对于这两类数据库,对方的优势就是自己的弱势,反之亦然。但是近年来这两种数据库都在向着另外一个方向进化。

例如:NOSQL数据库慢慢开始具备SQL数据库的一些复杂查询功能的雏形,比如Couchbase的index以及MONGO的复杂查询。对于事务的支持也可以用一些系统级的原子操作来实现例如乐观锁之类的方法来曲线救国。SQL数据库也开始慢慢进化,比如HandlerSocker技术的实现,可以在MYSQL上实现对于SQL层的穿透,用NOSQL的方式访问数据库,性能可以上可以达到甚至超越NOSQL数据库。可扩展性上例如Percona Server,可以实现无中心化的集群。虽然这两极都因为各自的弱势而开始进化出另一极的一些特性,但是这些特性的增加也会消弱其本来具备的优势,比如Couchbase上的index的增加会逐步降低数据库的读写性能。所以怎样构建系统的短期和长期存储策略,用好他们各自的强项是架构师需要好好考虑的重要问题。

python操作redis

redis的概念:

redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。

Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。

Redis的安装

Redis一般都是安装在linux系统中,具体安装步骤如下:

#cd /usr/local/src

#wget http://download.redis.io/releases/redis-3.0.1.tar.gz 

#tar xzf redis-3.0.1.tar.gz 

#cd redis-3.0.1 

#make

#src/redis-server &

检查redis是否正常启动

Ps –ef |grep redis

Netstat –lnp |grep 6379

python安装redis的模块

Pip install redis

redis是以key-value的形式存储的,所以我们在操作的时候。首先我们将redis所在主机的ip和发布端口作为参数实例化了一个对象r,然后执行set('hello','world'),这样我们就在内存中存储了一个key为hello,值为‘world’的项。我们可以理解为{'hello':'world'},当我们要读取的之后,keys()就是获得多有key值。

例子:

import redis

r = redis.Redis(host="192.168.1.1", port=6379)

r.set("hello", "world")

print(r.get("hello"))

print(r.keys())

# print(dir(r))

2.连接池

redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池

例子:

import redis

pool = redis.ConnectionPool(host="192.168.1.1")

r = redis.Redis(connection_pool=pool)

r.set("python", "study")

print(r.get("python"))

管道

redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。减少功耗

redis是一个cs模式的tcp server,使用和http类似的请求响应协议。一个client可以通过一个socket连接发起多个请求命令。每个请求命令发出后client通常会阻塞并等待redis服务处理,redis处理完后请求命令后会将结果通过响应报文返回给client。基本的通信过程如下:

Client: INCR X

Server: 1

Client: INCR X

Server: 2

Client: INCR X

Server: 3

Client: INCR X

Server: 4

基本上四个命令需要8个tcp报文才能完成。由于通信会有网络延迟,假如从client和server之间的包传输时间需要0.125秒。那么上面的四个命令8个报文至少会需要1秒才能完成。这样即使redis每秒能处理100个命令,而我们的client也只能一秒钟发出四个命令。这显示没有充分利用 redis的处理能力。除了可以利用mget,mset 之类的单条命令处理多个key的命令外我们还可以利用pipeline的方式从client打包多条命令一起发出,不需要等待单条命令的响应返回,而redis服务端会处理完多条命令后会将多条命令的处理结果打包到一起返回给客户端。通信过程如下:

Client: INCR X

Client: INCR X

Client: INCR X

Client: INCR X

Server: 1

Server: 2

Server: 3

Server: 4

假设不会因为tcp报文过长而被拆分。可能两个tcp报文就能完成四条命令,client可以将四个命令放到一个tcp报文一起发送,server则可以将四条命令的处理结果放到一个tcp报文返回。通过pipeline方式当有大批量的操作时候。我们可以节省很多原来浪费在网络延迟的时间。需要注意到是用 pipeline方式打包命令发送,redis必须在处理完所有命令前先缓存起所有命令的处理结果。打包的命令越多,缓存消耗内存也越多。所以并是不是打包的命令越多越好。具体多少合适需要根据具体情况测试

例子:

import datetime

import redis

def withpipe(r):

    pipe = r.pipeline(transaction=True)

    for i in xrange(1, 1000):

        key = "test1" +str(i)

        value = "test1" + str(i)

        pipe.set(key, value)

    pipe.execute()

def withoutpipe(r):

    # pipe = r.pipeline(transaction=True)

    for i in xrange(1, 1000):

        key = "test1" + str(i)

        value = "test1" + str(i)

        r.set(key, value)

if __name__ == "__main__":

    pool = redis.ConnectionPool(host="192.168.1.1", port=6379, db=0)

    r1 = redis.Redis(connection_pool=pool)

    r2 = redis.Redis(connection_pool=pool)

    start = datetime.datetime.now()

    # print(start)

    withpipe(r1)

    end = datetime.datetime.now()

    # print((end-start).microseconds)

    # print(end-start)

    t_time = (end - start).microseconds

    print("withpipe time is : {0}".format(t_time))

    start = datetime.datetime.now()

    withoutpipe(r2)

    end = datetime.datetime.now()

    t_time = (end - start).microseconds

    print("withoutpipe time is : {0}".format(t_time))

结果:

withpipe time is : 28000

withoutpipe time is : 253000



string操作

redis中的string在内存中都是按照一个key对应一个value来存储的。如:


r.set(“name”, “hahaxiangxiang”)

set(name, value, ex=None, px=None, nx=False, xx=False)

#ex,过期时间(秒)

#px,过期时间(毫秒)

#nx,如果设置为True,则只有name不存在时,当前set操作才执行,同setnx(name, value)

#xx,如果设置为True,则只有name存在时,当前set操作才执行'''


get(name)获取redis中的key值

print(r.get("name"))


mset()批量设置值

r.mset(name1="shang", name2="haha")

r.mset({"name3": "kong", "name4": "gu"})


mget(keys, *args)批量获取值

print(r.mget("name1", "name2", "name3", "name4"))

append(name, value)

r.append("name","lisi")

print(r.get("name"))



list操作

redis中的List在在内存中按照一个name对应一个List来存储

#在name对应的list中添加元素,每个新的元素都添加到列表的最左边

lpush(name,values)

r.lpush("list_name",2)

#保存在列表中的顺序为5,4,3,2

r.lpush("list_name",3,4,5)

#同lpush,但每个新的元素都添加到列表的最右边

rpush(name,values)

#在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边

lpushx(name,value)

#在name对应的list中添加元素,只有name已经存在时,值添加到列表的最右边

rpushx(name,value)

#name对应的list元素的个数

llen(name)

print(r.llen("list_name"))


#参数:name,redis的name;where,BEFORE或AFTER;refvalue,标杆值,即:在它前后插入数据;value,要插入的数据

linsert(name,where,refvalue,value):在name对应的列表的某一个值前后插入一个新值

#参数:name,redis的name;index,list的索引位置;value,要设置的值

r.lset(name,index,value):对name对应的list中的某一个索引位置重新赋值。

# 参数:name,redis的name;value,要删除的值;num:num=0,删除列表中所有的指定值;num=2,从前到后,删除2个;num=-2,从后向前,删除2个

r.lrem(name,value,num):在name对应的list中删除指定的值

#扩展: rpop(name) 表示从右向左操作

lpop(name):在name对应的列表的左侧获取第一个元素并在列表中移除,返回值删除那个元素的值


lindex(name,index):在name对应的列表中根据索引取列表元素

lrange(name,start,end):在name对应的列表分片获取数据

例子:

import redis


pool = redis.ConnectionPool(host="192.168.1.1", port=6379, db=0)

r = redis.Redis(connection_pool=pool)

# lpush  在list的左边增加一个元素           left

# rpush  在list的右边增加一个元素           right

r.lpush("list1", "test1")

r.rpush("list1", "haha")

r.lpush("list1", "test2")

r.lpush("list1", "test3")

r.lpush("list1", "test2")

r.lpush("list1", 2, 3, 4)

r.lpush("list1", "test2")

print(r.lrange("list1", 0, -1))


# 最终的list结果是    [4, 3, 2, "test3", "test2", "test1", "haha"]


# 在中间位置增加一个元素

# linsert(name,where,refvalue,value)

# name   代表的是list对应的key值

# where     AFTER   BEFORE

# refvalue    list中的某个元素

# value      你要增加的值是什么

r.linsert("list1", "AFTER",  "test2", "hello")

print(r.lrange("list1", 0, -1))

r.lset("list1", 2, "world")

# lset  更改某个元素的值

# r.lset(name,index,value)

print(r.lrange("list1", 0, -1))

print(r.lindex("list1", 2))

# lindex   查看list某个下标的值

print(r.lpop("list1"))

# lpop从list的最左边删除一个元素,返回删除元素的值

print(r.lrange("list1", 0, -1))

r.lrem("list1", "world")

# r.lrem(name,value,num):

print(r.lrange("list1", 0, -1))

结果:

['test2', '4', '3', '2', 'test2', 'test3', 'test2', 'test1', 'haha']

['test2', 'hello', '4', '3', '2', 'test2', 'test3', 'test2', 'test1', 'haha']

['test2', 'hello', 'world', '3', '2', 'test2', 'test3', 'test2', 'test1', 'haha']

world

test2

['hello', 'world', '3', '2', 'test2', 'test3', 'test2', 'test1', 'haha']

['hello', '3', '2', 'test2', 'test3', 'test2', 'test1', 'haha']



set操作

set集合就是不重复的列表


sadd(name,values)

#给name对应的集合中添加元素


r.sadd("set_name","aa")

r.sadd("set_name","aa","bb")

smembers(name)

#获取name对应的集合的所有成员

scard(name)

#获取name对应的集合中的元素个数

r.scard("set_name")

sinter(keys, *args)

# 获取多个name对应集合的并集

r.sadd("set_name","aa","bb")

r.sadd("set_name1","bb","cc")

r.sadd("set_name2","bb","cc","dd")


print(r.sinter("set_name","set_name1","set_name2"))

#输出:{bb}

sismember(name, value)

#检查value是否是name对应的集合内的元素

spop(name)

#从集合的右侧移除一个元素,并将其返回

sunion(keys, *args)

#获取多个name对应的集合的并集

r.sunion("set_name","set_name1","set_name2")

srem(name, value)  删除集合中的某个元素

r.srem("set_name", "aa")


Hash类型操作

Redis在内存中存储hash类型是以name对应一个字典形式存储的

hset(name,key,value)

    name:redis的name

    key:key1对应的hash中的key

    value:value1对应的hash中的value

name对应的hash中设置一个键值对(不存在,则创建;否则,修改),当name对应的hash中不存在当前key则创建(相当于添加)

hget(name,key)

在name对应的hash中获取根据key获取value

hmset(name,mapping)

    name:redis的name

    mapping:字典,如{'k1':'v1','k2','v2'}

在name对应的hash中批量设置键值对

例子:

import redis

pool = redis.ConnectionPool(host='192.168.1.1',port=6379)

r = redis.Redis(connection_pool=pool)

r.hmset('test',{'k1':'v1','k2':'v2'})

print(r.hmget('test','k1','k2'))

输出:

[b'v1', b'v2']

hmget(name,keys,*args)

    name:redis对应的name

    keys:要获取key的集合,如:['k1','k2','k3']

    *args:要获取的key,如:k1,k2,k3

在name对应的hash中获取多个key的值

例子:

import redis

pool = redis.ConnectionPool(host='192.168.10.128',port=6379)

r = redis.Redis(connection_pool=pool)

r.hmset('test',{'k1':'v1','k2':'v2'})

#获取多个值

print(r.hmget('test','k1','k2'))

hgetall(name)获取name对应hash的所有键值

例子:

import redis

pool = redis.ConnectionPool(host='192.168.10.128',port=6379)

r = redis.Redis(connection_pool=pool)

r.hmset('test',{'k1':'v1','k2':'v2'})

print(r.hgetall('test'))

输出:

{b'k2': b'v2', b'k1': b'v1'}

hlen(name):获取name对应的hash中键值的个数

例子:

import redis

pool = redis.ConnectionPool(host='192.168.10.128',port=6379)

r = redis.Redis(connection_pool=pool)

r.hmset('test',{'k1':'v1','k2':'v2'})

print(r.hlen('test'))

输出:

2

hkeys(name):获取name对应的hash中所有的key的值

hvals(name):获取name对应的hash中所有的value的值

例子:

import redis

pool = redis.ConnectionPool(host='192.168.10.128',port=6379)

r = redis.Redis(connection_pool=pool)

r.hmset('test',{'k1':'v1','k2':'v2'})

print(r.hkeys('test'))

print(r.hvals('test'))

输出:

[b'k2', b'k1']

[b'v2', b'v1']

hexists(name,key):检查name对应的hash是否存在当前传入的key

hdel(name,*keys):将name对应的hash中指定key的键值对删除

例子:

import redis

pool = redis.ConnectionPool(host='192.168.10.128',port=6379)

r = redis.Redis(connection_pool=pool)

r.hmset('test',{'k1':'v1','k2':'v2'})

print(r.exists('test'))

print(r.hdel('test','k1'))

print(r.hmget('test','k1','k2'))

 

输出:

True

1

其他常用操作

删除某个hash值

delete(*names)

根据name删除redis中的任意数据类型

exists(name)

检测redis的name是否存在

keys(pattern='*')

根据* ?等通配符匹配获取redis的name

expire(name ,time)

为某个name设置超时时间

rename(src, dst)

将redis的某个值移动到指定的db下

move 0

获取name对应值的类型

type(name)



本文转自 粗粮面包 51CTO博客,原文链接:http://blog.51cto.com/culiangmianbao/2044257,如需转载请自行联系原作者

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
4月前
|
NoSQL Unix 网络安全
【Azure Cache for Redis】Python Django-Redis连接Azure Redis服务遇上(104, 'Connection reset by peer')
【Azure Cache for Redis】Python Django-Redis连接Azure Redis服务遇上(104, 'Connection reset by peer')
【Azure Cache for Redis】Python Django-Redis连接Azure Redis服务遇上(104, 'Connection reset by peer')
|
3月前
|
NoSQL Linux Redis
linux安装单机版redis详细步骤,及python连接redis案例
这篇文章提供了在Linux系统中安装单机版Redis的详细步骤,并展示了如何配置Redis为systemctl启动,以及使用Python连接Redis进行数据操作的案例。
93 2
|
2月前
|
消息中间件 存储 NoSQL
python 使用redis实现支持优先级的消息队列详细说明和代码
python 使用redis实现支持优先级的消息队列详细说明和代码
48 0
|
5月前
|
安全 数据安全/隐私保护 Python
|
5月前
|
API Python
Python高手修炼手册:精通文件系统操作,掌控I/O管理,提升编程效率
【7月更文挑战第30天】在 Python 编程中, 文件系统操作与 I/O 管理是连接程序与数据的关键。初学者常因路径错误和权限问题受挫, 而高手能自如管理文件。传统 `os` 和 `os.path` 模块易出错, `pathlib` 提供了更直观的对象导向 API。I/O 方面, 同步操作会阻塞程序, 异步 (如使用 `aiofiles`) 则能大幅提升并发能力。真正的高手不仅掌握 API, 更能预见性能瓶颈并优化代码, 实现高效与优雅。
48 1
|
4月前
|
缓存 NoSQL 网络安全
【Azure Redis 缓存】 Python连接Azure Redis, 使用redis.ConnectionPool 出现 "ConnectionResetError: [Errno 104] Connection reset by peer"
【Azure Redis 缓存】 Python连接Azure Redis, 使用redis.ConnectionPool 出现 "ConnectionResetError: [Errno 104] Connection reset by peer"
|
4月前
|
缓存 监控 NoSQL
【Azure Redis 缓存】使用Python代码获取Azure Redis的监控指标值 (含Powershell脚本方式)
【Azure Redis 缓存】使用Python代码获取Azure Redis的监控指标值 (含Powershell脚本方式)
|
4月前
|
NoSQL 网络安全 Redis
用python安装redis并设置服务自启
用python安装redis并设置服务自启
31 0
|
6月前
|
存储 NoSQL Redis
Python—操作redis的一些心得
Python—操作redis的一些心得
30 0
|
存储 NoSQL Redis