Python标准库系列之Redis模块

本系列文章来源:<a>https://blog.ansheng.me/article/python-full-stack-way</a>

安装Redis

安装
模块GitHub地址:https://github.com/WoLpH/redis-py

[root@wangerxiao ~]#  yum -y install redis

配置绑定的IP

[root@wangerxiao ~]#  vim /etc/redis.conf 
bind 0.0.0.0

启动并设置开机自启动

[root@wangerxiao ~]# systemctl   start   redis 
[root@wangerxiao ~]# systemctl  enable  redis
Created symlink from /etc/systemd/system/multi-user.target.wants/redis.service to /usr/lib/systemd/system/redis.service.

检查
查看端口

[root@wangerxiao ~]# netstat -tlnp  | grep 'redis' 
tcp        0      0 127.0.0.1:6379          0.0.0.0:*               LISTEN      22867/redis-server  

数据写入测试

[root@wangerxiao ~]# redis-cli  
127.0.0.1:6379> set url https://blog.ansheng.me
OK
127.0.0.1:6379> get  url 
"https://blog.ansheng.me"
127.0.0.1:6379> exit

redis-py

安装redis-py

[root@wangerxiao ~]# pip install redis 

入门及使用

# 导入模块
In [1]: import redis
# 连接到Redis服务器
In [2]: conn = redis.Redis(host='127.0.0.1')
# 写入一条数据
In [3]: conn.set('name','wangerxiao')
Out[3]: True
# 获取一条数据
In [4]: conn.get('name') 
Out[4]: b'wangerxiao'

In [5]: conn.get('url') 
Out[5]: b'https://blog.ansheng.me'

使用连接池连接到Redis

In [6]: pool = redis.ConnectionPool(host='127.0.0.1')

In [7]: conn = redis.Redis(connection_pool=pool) 

In [8]: conn.set('hello','world') 
Out[8]: True

In [9]: conn.get('hello') 
Out[9]: b'world'

使用套接字连接

>>> r = redis.Redis(unix_socket_path='/tmp/redis.sock')

API

redis-py提供的API用来操作redis

String API

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

参数  描述
ex  过期时间(秒)
px  过期时间(毫秒)
nx  如果设置为True,则只有name不存在时,当前set操作才执行
xx  如果设置为True,则只有name存在时,岗前set操作才执行
In [13]: conn.set('k1','v1',ex=10,nx=True) 
Out[13]: True

In [14]: conn.get('k1')
Out[14]: b'v1'

In [15]: conn.get('k1')

setex(name, value, time)
设置过期时间/秒

In [16]: conn.setex('k','v',1) 
Out[16]: True

In [17]: conn.get('k') 

psetex(name, time_ms, value)
设置过期时间/毫秒

In [20]: conn.psetex('k',10,'v') 
Out[20]: True

In [21]: conn.get('k')

setnx(name, value)
设置值,只有key不存在时,执行设置操作

In [22]: conn.get('k1') 

In [23]: conn.setnx('k1','v1') 
Out[23]: True

In [24]: conn.get('k1') 
Out[24]: b'v1'

In [25]: conn.setnx('k1') 
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-25-9415152b10b5> in <module>()
----> 1 conn.setnx('k1')

TypeError: setnx() missing 1 required positional argument: 'value'

In [26]: conn.setnx('k1','v2')
Out[26]: False

mset(*args, **kwargs)
同时设置多个key/keys

>>> conn.mset(k1='v1', k2='v2')
True
>>> conn.mset({'k1':'v1', 'k1':'v1'})
True

get(name)
获取单个值

>>> conn.get('k1')
b'v1'

mget(keys, *args)
获取多个值

>>> conn.mget('k1','k2')
[b'v1', b'v2']
# 传入列表
>>> conn.mget(['name','url'])
[b'ansheng', b'https://blog.ansheng.me']

getset(name, value)
设置新值并获取原来的值

>>> conn.set('hello', 'world')
True
>>> result = conn.getset('hello', 'Linux')
>>> result
b'world'
>>> conn.get('hello')
b'Linux'

getrange(key, start, end)
通过索引的方式来获取value的值

>>> conn.set('key','value')
True
>>> conn.getrange('key', 1, 4)
b'alue'

setrange(name, offset, value)
根据索引修改value

>>> conn.set('n','123456789')
True
>>> conn.setrange('n', 0, 'a')
9
>>> conn.get('n')
b'a23456789'

setbit(name, offset, value)
getbit(name, offset)
获取value对应某一个索引位置对应的值0/1

>>> conn.getbit('k',1)
1

bitcount(key, start=None, end=None)
获取key对应二进制中表示1的个数
bitop(operation, dest, *keys)
将多个值进行值运算,得出的结果保存到一个新值当中

>>> conn.mset(n1='abc',n2='cde',n3='adc')
True
>>> conn.bitop('AND','now_key','n1','n2','n3')
3
>>> conn.get('now_key')
b'a`a'
>>> conn.mget('n1','n2','n3')
[b'abc', b'cde', b'adc']

operation支持AND(并)、OR(或)、NOT(非)、XOR(异或)

strlen(name)
获取value的长度

>>> conn.set('name','wangerxiao')
True
>>> conn.strlen('name')
10

incr(name, amount=1)
对name的value进行自增,如果name不存在则创建,否则自增

>>> conn.get('number')
>>> conn.incr('number')
1
>>> conn.get('number')
b'1'
>>> conn.incr('number')
2
>>> conn.incr('number', 10)
12

incrbyfloat(name, amount=1.0)
同上,支持浮点数自增

>>> conn.incrbyfloat('number', 1.5)
13.5
>>> conn.incrbyfloat('number', 1.1)
14.6
decr(name, amount=1)

自减,同自增一样,如果进行自减的value不是整数就报错

>>> conn.set('n', 10)
True
>>> conn.decr('n')
9
>>> conn.decr('n', 9)
0

append(key, value)
在value后面追加内容

>>> conn.set('blog','https://blog.ansheng.me')
True
>>> conn.append('blog','/')
26
>>> conn.get('blog')
b'https://blog.ansheng.me/'
Hash API

hset(name, key, value)
设置name的键值对,有则修改,没有则创建

>>> conn.hset('dic','k1','v1')
1
>>> conn.hget('dic','k1')
b'v1'

hmset(name, mapping)
同时设置多个name的key/value

>>> conn.hmset('dic', {'k1': 'v1', 'k2': 'v2'})
True
>>> conn.hget('dic','k2')
b'v2'

hget(name, key)
获取name中key的值

>>> conn.hget('dic','k2')
b'v2'
hmget(name, keys, *args)

同时获取多个

>>> conn.hmget('dic',['k1', 'k2'])
[b'v1', b'v2']
>>> conn.hmget('dic','k1', 'k2')
[b'v1', b'v2']

hgetall(name)
获取name对应的所有key/value

>>> conn.hgetall('dic')
{b'k1': b'v1', b'k2': b'v2'}

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

>>> conn.hlen('dic')
2

hkeys(name)
获取name中所有的key

>>> conn.hkeys('dic')
[b'k1', b'k2']

hvals(name)
获取name中所有的value

>>> conn.hvals('dic')
[b'v1', b'v2']

hexists(name, key)
检查当前name中是否有传入的key

>>> conn.hexists('dic','k1')
True
>>> conn.hexists('dic','kk')
False

hdel(self, name, *keys)
删除name中对应的key

>>> conn.hdel('dic','k1')
1
>>> conn.hget('dic','k1')

hincrby(name, key, amount=1)
name中key对应的value进行自增,如果不存在则创建

>>> conn.hincrby('dic','number')
1
>>> conn.hincrby('dic','number',10)
11

hincrbyfloat(name, key, amount=1.0)
value自增,支持浮点数,同上

>>> conn.hincrbyfloat('dic','float')
1.0
>>> conn.hincrbyfloat('dic','float',0.3)
1.3

hscan(name, cursor=0, match=None, count=None)
增量式迭代获取,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而防止内存被撑爆

参数  描述
name    redis的name
cursor  游标(基于游标分批取获取数据)
match   匹配指定key,默认None 表示所有的key
count   每次分片最少获取个数,默认None表示采用Redis的默认分片个数

hscan_iter(name, match=None, count=None)
利用yield封装hscan创建生成器,实现分批去redis中获取数据

参数  描述
match   匹配指定key,默认None 表示所有的key
count   每次分片最少获取个数,默认None表示采用Redis的默认分片个数

如:

for item in r.hscan_iter('xx'):
    print item

expire(name, time)
设置过期时间

>>> conn.hset('info','BlogUrl','https://blog.ansheng.me')
1
>>> conn.expire('info', 10)
True
>>> conn.hget('info','BlogUrl')
b'https://blog.ansheng.me'
>>> conn.hget('info','BlogUrl')
ListAPI

lpush(name, *values)
在最左边添加值

>>> conn.lpush('li', 11,22,33)
3
>>> conn.lindex('li', 0)
b'33'

rpush(name, *values)
在最右边添加值

>>> conn.rpush('lli', 11,22,33)
3
>>> conn.lindex('lli', 0)
b'11'

lpushx(name, value)
只有name已经存在时,值添加到列表的最左边

>>> conn.lpushx('li', 'aa')
4
>>> conn.lindex('li', 0)
b'aa'

rpushx(name, value)
只有name已经存在时,值添加到列表的最右边

>>> conn.rpushx('li', 'bb')
5
>>> conn.lindex('li', 0)
b'aa'
>>> conn.lindex('li', 4)
b'bb'

llen(name)
获取name元素的个数

>>> conn.llen('li')
5

linsert(name, where, refvalue, value)
在name的某一个值前面或者后面插入一个新值

>>> conn.linsert('li','AFTER','11','cc')
6
>>> conn.lindex('li', 3)
b'11'
>>> conn.lindex('li', 4)
b'cc'

lset(name, index, value)
对name中index索引位置的值进行重新赋值

>>> conn.lindex('li', 4)
b'cc'
>>> conn.lset('li', 4, 'hello')
True
>>> conn.lindex('li', 4)
b'hello'

lrem(name, value, num=0)
删除指定value后面或者前面的值

num=2,从前到后,删除2个;
num=-2,从后向前,删除2个

>>> conn.llen('li')
6
>>> conn.lrem('li', 'hello')
1
>>> conn.llen('li')
5
>>> conn.lrem('li', '22', num=2)
2
>>> conn.llen('li')
3

lpop(name)
删除name中左侧第一个元素

>>> conn.lindex('li', 0)
b'11'
>>> conn.lpop('li')
b'11'

rpop(name)
删除name中右侧第一个元素

>>> conn.rpop('li')
b'33'

lindex(name, index)
获取name中对应索引的值

>>> conn.lindex('li', 0)
b'aa'

lrange(name, start, end)
使用切片获取数据

>>> conn.llen('li')
8
>>> conn.lrange('li',0,5)
[b'3', b'23', b'34', b'235', b'2', b'1']

ltrim(name, start, end)
在name对应的列表中移除没有在start-end索引之间的值

>>> conn.ltrim('li',0,5)
True
>>> conn.llen('li')
6

rpoplpush(src, dst)
从src列表中取出最右边的元素,同时将其添加至dst列表的最左边

>>> conn.lpush('li1', 1,2,3)
3
>>> conn.lpush('li2', 'a','b','c')
3
>>> conn.rpoplpush('li1','li2')
b'1'

blpop(keys, timeout=0) brpop(keys, timeout=0)
brpoplpush(src, dst, timeout=0)

从src列表的右侧移除一个元素并将其添加到dst列表的左侧

>>> conn.lpush('ll', 'a','b','c')
3
>>> conn.lpush('aa', 'a','b','c')
3
>>> conn.brpoplpush('ll','aa')
b'a'

timeout,当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞

自定义增量迭代

由于redis类库中没有提供对列表元素的增量迭代,如果想要循环name对应的列表的所有元素,那么就需要:
1.获取name对应的所有列表
2.循环列表

但是,如果列表非常大,那么就有可能在第一步时就将程序的内容撑爆,所有有必要自定义一个增量迭代的功能:

def list_iter(name):
    """
    自定义redis列表增量迭代
    :param name: redis中的name,即:迭代name对应的列表
    :return: yield 返回 列表元素
    """
    list_count = r.llen(name)
    for index in xrange(list_count):
        yield r.lindex(name, index)
使用

for item in list_iter('pp'):
    print item
SET API

sadd(name, *values)
为name添加值,如果存在则不添加

>>> conn.sadd('s1', 1)
1
>>> conn.sadd('s1', 1)
0

scard(name)
返回name的元素数量

>>> conn.scard('s1')
1

sdiff(keys, *args)
在keys集合中不在其他集合中的数据

>>> conn.sdiff('s1','s2')
{b'c', b'v', b'a'}

sdiffstore(dest, keys, *args)
在keys集合中不在其他集合中的数据保存到dest集合中

>>> conn.sdiffstore('news','s1','s2')
3
>>> conn.scard('news')
3

sinter(keys, *args)
获取keys集合中与其他集合中的并集

>>> conn.sinter('s1','s2')
{b'2', b'3', b'1'}

sinterstore(dest, keys, *args)
获取keys集合中与其他集合中的并集数据并保存到dest集合中

>>> conn.sinterstore('news1','s1','s2')
3

sismember(name, value)
获取value是否是name集合中的成员

>>> conn.sismember('news1','1')
True
>>> conn.sismember('news1','aa1')
False

smembers(name)
获取name集合中所有的成员

>>> conn.smembers('news1')
{b'2', b'3', b'1'}

smove(src, dst, value)
将src中的value移动到dst中

>>> conn.smembers('s1')
{b'c', b'2', b'v', b'1', b'3', b'a'}
>>> conn.smembers('s2')
{b'2', b'3', b'1'}
>>> conn.smove('s1','s2','v')
True
>>> conn.smembers('s1')
{b'c', b'2', b'a', b'3', b'1'}
>>> conn.smembers('s2')
{b'2', b'v', b'3', b'1'}

spop(name)
删除并返回name中的随机成员

>>> conn.smembers('s2')
{b'2', b'v', b'3', b'1'}
>>> conn.spop('s2')
b'3'
>>> conn.smembers('s2')
{b'2', b'v', b'1'}
>>> conn.spop('s2')
b'2'
>>> conn.smembers('s2')
{b'v', b'1'}
>>> conn.spop('s2')
b'1'
>>> conn.smembers('s2')
{b'v'}

srandmember(name, number=None)
随机获取name集合中的number个成员,默认number=1

>>> conn.smembers('s1')
{b'c', b'2', b'a', b'3', b'1'}
>>> conn.srandmember('s1')
b'1'
>>> conn.srandmember('s1')
b'a'
>>> conn.srandmember('s1',number=2)
[b'3', b'a']
>>> conn.srandmember('s1',number=2)
[b'1', b'2']

srem(name, *values)
删除name集合中的values数据

>>> conn.smembers('s1')
{b'c', b'2', b'a', b'3', b'1'}
>>> conn.srem('s1','1','2')
2
>>> conn.smembers('s1')
{b'c', b'a', b'3'}

sunion(keys, *args)
获取keys集合与其他集合的并集

>>> conn.sadd('a1',1,2,3)
3
>>> conn.sadd('a2',1,2,3,4,5,6,7)
7
>>> conn.sunion('a2','a1')
{b'2', b'7', b'1', b'3', b'6', b'5', b'4'}

sunionstore(dest, keys, *args)
获取keys集合与其他集合的并集并保存到dest中

>>> conn.sunionstore('a3', 'a2','a1')
7
>>> conn.smembers('a3')
{b'2', b'7', b'1', b'3', b'6', b'5', b'4'}
Ordered set API

zadd(name, *args, **kwargs)

>>> conn.zadd('h1','n1',11,'n2',22)
2
>>> conn.zadd('h2',n1=11,n2=22)
2

zcard(name)
返回有序集合name元素的数量

>>> conn.zcard('h1')
2

zcount(name, min, max)
返回在name中值在min与max之间的值个数

>>> conn.zcount('h1',10,30)
2

zincrby(name, value, amount=1)
name中让value的值加上amount

>>> conn.zincrby('h1','n1',10)
21.0

zinterstore(dest, keys, aggregate=None) zlexcount(name, min, max)

zrange(name, start, end, desc=False, withscores=False, score_cast_func=float)

参数  描述
name    redis的name
start   有序集合索引起始位置(非分数)
end 有序集合索引结束位置(非分数)
desc    排序规则,默认按照分数从小到大排序
withscores  是否获取元素的分数,默认只获取元素的值
score_cast_func 对分数进行数据转换的函数
>>> conn.zrange('h1', 1, 2, desc=True, withscores=True, score_cast_func=float)
[(b'n1', 21.0)]
>>> conn.zrange('h1', 1, 2, desc=False, withscores=True, score_cast_func=float)
[(b'n2', 22.0)]
# 从大到小排序
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)

zrangebylex(name, min, max, start=None, num=None)

当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的 值 (lexicographical ordering)来进行排序,而这个命令则可以返回给定的有序集合键 key 中, 元素的值介于 min 和 max 之间的成员

对集合中的每个成员进行逐个字节的对比(byte-by-byte compare), 并按照从低到高的顺序, 返回排序后的集合成员。 如果两个字符串有一部分内容是相同的话, 那么命令会认为较长的字符串比较短的字符串要大

参数  描述
name    redis的name
min 左区间(值) + 表示正无限; - 表示负无限; ( 表示开区间; [ 则表示闭区间
min 右区间(值)
start   对结果进行分片处理,索引位置
num 对结果进行分片处理,索引后面的num个元素

如:

ZADD myzset 0 aa 0 ba 0 ca 0 da 0 ea 0 fa 0 ga
# r.zrangebylex('myzset', "-", "[ca") 结果为:['aa', 'ba', 'ca']

更多:

# 从大到小排序
zrevrangebylex(name, max, min, start=None, num=None)

zrevrangebylex(name, max, min, start=None, num=None)

zrangebyscore(name, min, max, start=None, num=None, withscores=False, score_cast_func=float)**

zrank(name, value)

返回基于0的值,指示在排序集名称的值排名

>>> conn.zrank('h1','n1')
0
>>> conn.zrank('h1','n2')
1

zrevrank(name, value),从大到小排序

zrem(name, *values)
删除name中对应的values

>>> conn.zrem('h1','n2')
1
>>> conn.zrem('h2',['n1','n2'])
2

zremrangebyrank(name, min, max)
根据排行范围进行删除

>>> conn.zremrangebyrank('h1',1,2)
1
zremrangebyscore(name, min, max)

根据分数范围进行删除

>>> conn.zremrangebyscore('h1',10,20)
2

zscore(name, value)
返回指定value的值是多少

>>> conn.zscore('h1','n1')
11.0

zunionstore(dest, keys, aggregate=None)

Global API(全局)

在redis中删除names

>>> conn.delete('ooo')
1

exists(name)
检测name是否存在

>>> conn.exists('iii')
False
>>> conn.exists('h1')
True

keys(pattern=’*’)

# 匹配数据库中所有 key 
>>> conn.keys(pattern='*')
# 匹配hello,hallo和hxllo等
conn.keys(pattern='h?llo')
# 匹配hllo和heeeeello 等
conn.keys(pattern='h*llo')
# 匹配hello和hallo,但不匹配 hillo
conn.keys(pattern='h[ae]llo')

rename(src, dst)
把src重命名成dst

>>> conn.set('k','v')
True
>>> conn.get('k')
b'v'
>>> conn.rename('k', 'kk')
True
>>> conn.get('k')
>>> conn.get('kk')
b'v'

move(name, db)
将redis的某个值移动到指定的db下

randomkey()
随机获取一个redis的name,不进行删除

>>> conn.randomkey()
b'll'
>>> conn.randomkey()
b'news1'

type(name)
查看name的类型

>>> conn.type('kk')
b'string'
管道

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

>>> import redis
>>> pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
>>> r = redis.Redis(connection_pool=pool)
# 创建一个通道支持事务
>>> pipe = r.pipeline(transaction=True)
#
>>> r.set('hello', 'world')
True
>>> r.set('blog', 'ansheng.me')
True
# 如果在设置上面两个值的过程中出错了,那么这次提交就不会执行
>>> pipe.execute()
[]
发布订阅
# monitor.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import redis

class RedisHelper:
    def __init__(self):
        self.__conn = redis.Redis(host='192.168.56.100')
        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

# subscriber.py 订阅者
#!/usr/bin/env python
# -*- coding:utf-8 -*-

from monitor import RedisHelper

obj = RedisHelper()
redis_sub = obj.subscribe()

while True:
    msg = redis_sub.parse_response()
    print(msg)

# announcer.py 发布者
#!/usr/bin/env python
# -*- coding:utf-8 -*-

from monitor import RedisHelper

obj = RedisHelper()
obj.public('hello')
实例

让redis缓存tornado页面

# _*_coding:utf-8 _*_

import tornado.ioloop
import tornado.web
import time
import redis

poll = redis.ConnectionPool(host='192.168.56.100', port=6379)
conn = redis.Redis(connection_pool=poll)

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        CurrentTim = conn.get('CurrentTim')
        if CurrentTim:
            self.write(CurrentTim)
        else:
            CurrentTim = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
            conn.set('CurrentTim', CurrentTim, ex=5)
            self.write(CurrentTim)

settings = {
    "tempalte_path": "template",
}

application = tornado.web.Application([
    (r'/', MainHandler),
], **settings)

if __name__ == "__main__":
    application.listen(9999)
    tornado.ioloop.IOLoop.instance().start()

基于Redis的Session存储

app.py

# _*_coding:utf-8 _*_

import tornado.ioloop
import tornado.web
import RedisToSession

class BaseHandler(tornado.web.RequestHandler):
    def initialize(self):
        self.session = RedisToSession.Session(self)

class MainHandler(BaseHandler):
    def get(self):
        Info = self.session.GetAll()

        self.render("template/index.html", Data=Info)

    def post(self, *args, **kwargs):
        # 获取传过来的值
        Key = self.get_argument('key')
        Val = self.get_argument('val')
        action = self.get_argument('action')
        if action == 'set':
            # 设置值
            self.session[Key] = Val
        elif action == 'del':
            del self.session[Key]

        # 获取所有信息
        Info = self.session.GetAll()
        # 返回给前端渲染
        self.render("template/index.html", Data=Info)

settings = {
    "tempalte_path": "template",
    "cookie_secret": "508CE6152CB93994628D3E99934B83CC",
}

application = tornado.web.Application([
    (r'/', MainHandler),
], **settings)

if __name__ == "__main__":
    application.listen(9999)
    tornado.ioloop.IOLoop.instance().start()

template\index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>

<form action="/" method="post">
    set/del:<input type="text" name="action" value="set"/>
    Key: <input type="text" name="key"/>
    Val: <input type="text" name="val"/>
    <input type="submit" value="设置"/>
</form>



</body>
</html>

RedisToSession.py

# _*_ coding: utf-8 _*_

import redis
import hashlib
import uuid
import json

# 连接memcached
pool = redis.ConnectionPool(host='192.168.56.100', port=6379)
conn = redis.Redis(connection_pool=pool)


class Session:
    CookieID = 'uc'
    ExpiresTime = 60 * 20

    def __init__(self, handler):
        """
        用于创建用户session在redis中的字典
        :param handler: 请求头
        """
        self.handler = handler
        # 从客户端获取随机字符串
        SessionID = self.handler.get_secure_cookie(Session.CookieID, None)
        # 客户端存在并且在服务端也存在
        if SessionID and conn.exists(SessionID):
            self.SessionID = SessionID
        else:
            # 获取随机字符串
            self.SessionID = self.SessionKey()
            # 把随机字符串写入memcached,时间是20分钟
            conn.hset(self.SessionID, None, None)

        # 每次访问超时时间就加20分钟
        conn.expire(self.SessionID, Session.ExpiresTime)

        # 设置Cookie
        self.handler.set_secure_cookie('uc', self.SessionID)

    def SessionKey(self):
        """
        :return: 生成随机字符串
        """
        UUID = str(uuid.uuid1()).replace('-', '')
        MD5 = hashlib.md5()
        MD5.update(bytes(UUID, encoding='utf-8'))
        SessionKey = MD5.hexdigest()
        return SessionKey

    def __setitem__(self, key, value):
        """
        :param key: session信息中的key
        :param value: 对应的Value
        """
        conn.hset(self.SessionID, key, value)

    def __getitem__(self, item):
        """
        :param item: Session信息中对应的Key
        :return: 获取的Session信息
        """
        # 获取对应的数据
        ResultData = conn.hget(self.SessionID, item)
        return ResultData

    def __delitem__(self, key):
        """
        :param key: 要删除的Key
        """
        conn.hdel(self.SessionID, key)

    def GetAll(self):
        # 获取Session中所有的信息,仅用于测试
        SessionData = conn.hgetall(self.SessionID)
        return SessionData
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,907评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,546评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,705评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,624评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,940评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,371评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,672评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,396评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,069评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,350评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,876评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,243评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,847评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,004评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,755评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,378评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,266评论 2 259

推荐阅读更多精彩内容

  • 1、redis连接 redis提供两个类Redis和StrictRedis用于实现Redis的命令,StrictR...
    君惜丶阅读 229,029评论 15 117
  • 连接数据库 StrictRedis ConnectionPool 构造url方式连接到数据库,有以下三种模式: S...
    cnkai阅读 3,008评论 0 2
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,087评论 18 139
  • Redis 数据结构简介 Redis 可以存储键与5种不同数据结构类型之间的映射,这5种数据结构类型分别为Stri...
    DreamerRzc阅读 236,169评论 26 271
  • 爱情。环保。与我无关。我脑子里从头到尾竟只徘徊着张雨绮的那句话:基因不同。 也许我早该明白,很多事情不是想象的那么...
    守岸_阅读 345评论 4 0