浅学Redis

一、Redis介绍

1、什么是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可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。

img

2、总结

redis介绍总结:

  • 1、redis是缓存数据库
  • 2、redis是非关系型数据库。k-v键值对存储数据,没有表的概念
  • 3、redis是C语言编写的服务,速度非常快

redis为什么速度那么快:

  • 1、纯内存操作所以速度如此之快
  • 2、网络模型使用的IO多路复用所以高并发
  • 3、6.X版本之前都是单进程、单线程架构,没有线程进程件切换因此资源消耗更少

二、Redis安装与启动

1、Redis安装步骤

2、Redis启动服务

  • 方式一:

    在计算机服务里手动启动redis服务

    右键点击此电脑→→管理→→服务与应用程序→→服务→→找到Redis双击打开→→启动

  • 方式二:

    在cmd终端下输入一下两个命令即可启动

    redis-server  # 启动服务端
    

    ppmV05n.png

    redis-cli  # 启动服务端
    

    ppmVTxK.png

3、图形化界面使用Redis

  • Redis的图形化客户端有很多,这里推荐使用Redis Desktop Manager

    -Redis Desktop Manager :开源的,原来免费,后来收费了  推荐用(mac,win,linux 都有)
        -Qt5  qt是个平台,专门用来做图形化界面的 
        -可以使用c++写
        -可以使用python写  pyqt5  使用python写图形化界面 (少量公司再用)
        -安装包:resp-2022.1.0.0.exe 一路下一步,安装完启动起来
    
  • 安装resp

    下载安装包后,一路下一步安装即可

    安装成功后打开软件,会出现连接配置窗口,我们点击左边的新建连接后,会出现下图窗口

    接着我们输入配置信息,测试连接成功后,点击确认即可

    img

    通过图形化界面,我们可以看到redis默认有16个库,默认连进去就是第0个

    ps:我们在连接的时候也可以使用redis协议连接

    img

    img

三、Redis普通连接和连接池

1、简单使用方式

在cmd中,redis的简单使用方式如下

127.0.0.1:6379> set name zsm
OK
127.0.0.1:6379> get name
"zsm"

ppmmQUJ.png

2、pycharm使用redis准备工作

使用pycharm操作redis的时候,pycharm就相当于一个客户端

打开pycharm后,打开terminal界面,输入命令安装redis模块

pip install redis
  • 普通连接

    # 1、导入模块的Redis类
    from redis import Redis
    
    # 2、实例化得到对象
    conn = Redis(host='127.0.0.1', port=6379)
    
    # 3、使用conn,操作redis
    ## 设置值
    conn.set('name','jason')
    ## 取值
    res = conn.get('name')  # 返回数据时bytes格式
    
    conn.close()
    
  • 连接池连接

    前面我们提到redis服务支持高并发,而redis是基于socket建立连接的,在客户端主动断开连接之前,会一直保持连接的状态

    因此当访问量很大的时候,上面的代码就会出现连接数量太大,线程太多,导致性能降低的情况

    因此我们这里用连接池来限制最大的连接数量

    ps:这里可以跟mysql对比记忆,mysql没有使用连接池,一个请求就会创建一个连接,并发数过高也会导致性能降低(但是我们可以自行创建,django-db-connection-pool模块)

    简单实现线程池

    这里只是编写了线程池

    import redis
    
    POOL = redis.ConnectionPool(max_connections=10, host='127.0.0.1', port=6379)
    
    con = redis.Redis(connection_pool=POOL)
    
    print(con.get('name'))
    
    con.close()
    
    多线程测试连接池

    这里我们利用多线程测试连接池的工作情况

    在测试的时候我们会发现,当连接池全被占用后,其他线程会因为没有连接可用,而报错,但是并不影响后续的线程运行

    我们把连接池的对象POOL当成配置文件存到pool.py中,因为连接池需要做成单例模式,否侧就会在创建线程的时候,创建新的连接池,更加降低性能

    pool.py

    import redis
    
    POOL = redis.ConnectionPool(max_connections=10, host='127.0.0.1', port=6379)  # 创建一个大小为10的redis连接池
    

    测试代码

    from threading import Thread
    import redis
    from pool import POOL
    '''
    要把POOL做成单例,否则有可能,在每个线程中创建了一个池,从池中拿一个连接,性能更低
    多种方式,使用模块导入的方式
    多种方式,使用模块导入的方式
    '''
    
    
    def task():
        con = redis.Redis(connection_pool=POOL)
        print(con.get('name'))
    
    for i in range(100):
        t = Thread(target=task)
        t.start()
    

四、Redis五大数据类型

5种数据类型,value类型
	-字符串:用的最多,做缓存;做计数器
    -列表: 简单的消息队列
    -字典(一些语言叫他hash):缓存
    -集合:去重
    -有序集合:排行榜
redis={
        k1:'123',      字符串
        k2:[1,2,3,4],   列表/数组
        k3:{1,2,3,4}     集合
        k4:{name:lqz,age:12}  字典/哈希表
        k5:{('lqz',18),('egon',33)}  有序集合
}

img

1、String(字符串类型)

String操作,redis中的String在在内存中按照一个name对应一个value来存储。如图:

img

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

    在Redis中设置值,默认,不存在创建,存在则修改
    
    参数:
        ex:过期时间(秒)
        px:过期时间(毫秒)
        nx:如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没结果
        xx:如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
    
  • setnx(name, value)

    设置值,只有name不存在时,执行设置操作(添加),如果存在,不会修改
    相当于:
    	set('name','jason',nx=True)
    
  • setex(name, value, time)

    设置值
    参数:
        time,过期时间(数字秒 或 timedelta对象)
        setex('name', 3, 'jason')
    等同于:
        set('name', 'jason', ex=3)
        
    
  • psetex(name, time_ms, value)

    设置值
    参数:
        time_ms,过期时间(数字毫秒 或 timedelta对象)
        psetex('name', 3000, 'jason') 
    等同于:
        set('name', 'jason', px=3)       
    
  • mset(*args, **kwargs)

    批量设置值
    如:
        mset(k1='v1', k2='v2')
    
  • get(name)

    获取值
    
  • mget(keys, *args)

    批量获取
    如:
        mget('k1', 'k2')
        或
        r.mget(['k3', 'k4'])
    
  • getset(name, value)

    设置新值并获取原来的值
    getset('wife','迪丽热巴')
    
  • getrange(key, start, end)

    获取子序列(根据字节获取,非字符)
    参数:
        name,Redis 的 name
        start,起始位置(字节)
        end,结束位置(字节)
        不是字符长度  前闭后闭区间
        getrange('wife', 0, 2)
    如: "迪丽热巴" ,0-3表示 "迪"
    
  • setrange(name, offset, value)

    修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
    参数:
        offset,字符串的索引,字节(一个汉字三个字节)
        value,要设置的值
        setrange('wife',2,'bbb')
    
  • setbit(name, offset, value)

    对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"
    
  • getbit(name, offset)

    获取name对应的值的二进制表示中的某位的值 (0或1)
    
  • bitcount(key, start=None, end=None)

    获取name对应的值的二进制表示中 1 的个数
    参数:
        key,Redis的name
        start,位起始位置
        end,位结束位置
    
  • bitop(operation, dest, *keys)

    获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值
     
    参数:
        operation,AND(并) 、 OR(或) 、 NOT(非) 、 XOR(异或)
        dest, 新的Redis的name
        *keys,要查找的Redis的name
     
    如:
      bitop("AND", 'new_name', 'n1', 'n2', 'n3')
        获取Redis中n1,n2,n3对应的值,然后讲所有的值做位运算(求并集),然后将结果保存 new_name 对应的值中
    
  • strlen(name)

    返回name对应值的字节长度(一个汉字3个字节)
    
  • incr(self, name, amount=1)

    自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
     
    参数:
        name,Redis的name
        amount,自增数(必须是整数)
     
    注:同incrby
    
  • incrbyfloat(self, name, amount=1.0)

    自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
     
    参数:
        name,Redis的name
        amount,自增数(浮点型)
    
  • decr(self, name, amount=1)

    自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
     
    参数:
        name,Redis的name
        amount,自减数(整数)
    
  • append(key, value)

    在redis name对应的值后面追加内容
     
    参数:
        key, redis的name
        value, 要追加的字符串
    
  • 操作代码
    import redis
    
    conn = redis.Redis()
    
    # 1 set(name, value, ex=None, px=None, nx=False, xx=False)
    # ex,过期时间(秒)
    # px,过期时间(毫秒)
    # nx,如果设置为True,则只有name不存在时,当前set操作才执行, 值存在,就修改不了,执行没效果
    # xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
    # conn.set('hobby','篮球',ex=3)
    # conn.set('hobby','篮球',px=3)
    # conn.set('name','lqz',nx=True)
    # conn.set('name','lqz',nx=False)
    # conn.set('hobby','篮球',xx=True)
    # conn.set('hobby','篮球',xx=False)
    # redis---》实现分布式锁,底层基于nx实现的
    
    
    # 2 setnx(name, value)
    # 等同于:conn.set('name','lqz',nx=True)
    # conn.setnx('name', '刘亦菲')
    
    # 3 setex(name, value, time)
    # 等同于:conn.set('name','lqz',ex=3)
    # conn.setex('wife', 3, '刘亦菲')
    
    
    # 4 psetex(name, time_ms, value)
    # conn.psetex('wife',3000,'刘亦菲')
    
    
    # 5 mset(*args, **kwargs)
    # conn.mset({'wife': '刘亦菲', 'hobby': '篮球'})
    
    
    # 6 get(name)
    # print(str(conn.get('wife'),encoding='utf-8'))
    # print(conn.get('wife'))
    
    
    # 7 mget(keys, *args)
    # res=conn.mget('wife','hobby')
    # res=conn.mget(['wife','hobby'])
    # print(res)
    
    
    # 8 getset(name, value)
    # res=str(conn.getset('wife','迪丽热巴'),encoding='utf-8')
    # res=conn.getset('wife','迪丽热巴')
    # print(res)
    
    
    # 9 getrange(key, start, end)
    # res = str(conn.getrange('wife', 0, 2), encoding='utf-8')  # 字节长度,不是字符长度  前闭后闭区间
    # print(res)
    
    
    # 10 setrange(name, offset, value)
    # conn.setrange('wife',2,'bbb')
    
    # ---- 比特位---操作
    # 11 setbit(name, offset, value)
    # 12 getbit(name, offset)
    # 13 bitcount(key, start=None, end=None)
    # ---- 比特位---操作
    
    # 14 bitop(operation, dest, *keys)   获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值
    
    
    # 15 strlen(name)
    # res=conn.strlen('hobby')   # 统计字节长度
    # print(res)
    
    
    # 16 incr(self, name, amount=1)
    # 自增,不会出并发安全问题,单线程架构,并发量高
    # conn.incr('age')
    # # incrby
    # 17 incrbyfloat(self, name, amount=1.0)
    # conn.incrbyfloat('age',1.2)
    
    
    # 18 decr(self, name, amount=1)
    # conn.decrby('age')
    # conn.decrby('age',-1)
    
    
    # 19 append(key, value)
    # conn.append('hobby','sb')
    
    print(conn.strlen('hobby'))
    
    conn.close()
    

    img

我们需要记住的字符串类型的操作

set 添加值
get 获取值
strlen 字节长度
incr 自增1

2、List(列表类型)

List操作,redis中的List在在内存中按照一个name对应一个List来存储。如图:

img

  • lpush(name,values)

    # 在name对应的list中添加元素,每个新的元素都添加到列表的最左边
     
    # 如:
        # r.lpush('oo', 11,22,33)
        # 保存顺序为: 33,22,11
     
    # 扩展:
        # rpush(name, values) 表示从右向左操作
    
  • lpushx(name,value)

    # 在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边
     
    # 更多:
        # rpushx(name, value) 表示从右向左操作
    
  • llen(name)

    # name对应的list元素的个数
    
  • linsert(name, where, refvalue, value))

    # 在name对应的列表的某一个值前或后插入一个新值
     
    # 参数:
        # name,redis的name
        # where,BEFORE或AFTER(小写也可以)
        # refvalue,标杆值,即:在它前后插入数据(如果存在多个标杆值,以找到的第一个为准)
        # value,要插入的数据
    
  • r.lset(name, index, value)

    # 对name对应的list中的某一个索引位置重新赋值
     
    # 参数:
        # name,redis的name
        # index,list的索引位置
        # value,要设置的值
    
  • r.lrem(name, value, num)

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

    # 在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素
     
    # 更多:
        # rpop(name) 表示从右向左操作
    
  • lindex(name, index)

    在name对应的列表中根据索引获取列表元素
    
  • lrange(name, start, end)

    # 在name对应的列表分片获取数据
    # 参数:
        # name,redis的name
        # start,索引的起始位置
        # end,索引结束位置  print(re.lrange('aa',0,re.llen('aa')))
    
  • ltrim(name, start, end)

    # 在name对应的列表中移除没有在start-end索引之间的值
    # 参数:
        # name,redis的name
        # start,索引的起始位置
        # end,索引结束位置(大于列表长度,则代表不移除任何)
    
  • rpoplpush(src, dst)

    # 从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边
    # 参数:
        # src,要取数据的列表的name
        # dst,要添加数据的列表的name
    
  • blpop(keys, timeout)

    # 将多个列表排列,按照从左到右去pop对应列表的元素
     
    # 参数:
        # keys,redis的name的集合
        # timeout,超时时间,当元素所有列表的元素获取完之后,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞
     
    # 更多:
        # r.brpop(keys, timeout),从右向左获取数据爬虫实现简单分布式:多个url放到列表里,往里不停放URL,程序循环取值,但是只能一台机器运行取值,可以把url放到redis中,多台机器从redis中取值,爬取数据,实现简单分布式
    
  • brpoplpush(src, dst, timeout=0)

    # 从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧
     
    # 参数:
        # src,取出并要移除元素的列表对应的name
        # dst,要插入元素的列表对应的name
        # timeout,当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞
    
  • 操作代码
    import redis
    
    conn = redis.Redis()
    # 1 lpush(name, values)   从错侧插入
    # conn.lpush('girls', '刘亦菲', '迪丽热巴')
    # conn.lpush('girls', '周淑怡')
    
    # 2 rpush(name, values) 表示从右向左操作
    # conn.rpush('girls', '小红')
    
    # 3 lpushx(name, value)
    # conn.lpushx('boys','小刚')
    # conn.lpush('boys','小刚')
    # conn.lpushx('girls','小刚')
    
    
    # 4 rpushx(name, value) 表示从右向左操作
    
    
    # 5 llen(name)
    # res = conn.llen('girls')
    # print(res)
    # 6 linsert(name, where, refvalue, value))
    
    # conn.linsert('girls','before','迪丽热巴','古力娜扎')
    # conn.linsert('girls', 'after', '小红', '小绿')
    
    # conn.linsert('girls', 'after', '小黑', '小嘿嘿')  # 没有标杆,插入不进去
    
    
    # 7 r.lset(name, index, value)  # 按位置改值
    # conn.lset('girls',1,'xxx')
    
    # 8 r.lrem(name, value, num)
    
    # conn.lrem('girls',1,'xxx')  # 从左侧开始,删除1个
    # conn.lrem('girls',-1,'xxx')  # 从右侧开始,删除1个
    # conn.lrem('girls',0,'xxx')  # 从左开始,全删除
    
    # 9 lpop(name)
    # res=conn.lpop('girls')
    # print(res)
    
    
    # 10 rpop(name) 表示从右向左操作
    
    # 11 lindex(name, index)
    # res = str(conn.lindex('girls', 1), encoding='utf-8')
    # print(res)
    
    # 12 lrange(name, start, end)
    # res=conn.lrange('girls',0,0)   # 前闭后闭区间
    # print(res)
    
    
    # 13 ltrim(name, start, end)
    # conn.ltrim('girls',2,3)
    
    
    # 14 rpoplpush(src, dst)
    
    # 15 blpop(keys, timeout)  # 记住 ,可以做消息队列使用  阻塞式弹出,如果没有,就阻塞
    # res=conn.blpop('boys')
    # print(res)
    
    # 16 r.brpop(keys, timeout),从右向左获取数据
    # 17 brpoplpush(src, dst, timeout=0)
    
    conn.close()
    

我们需要记住的列表类型的操作

lpush
lpop
llen
lrange

3、Hash(哈希类型)

Hash操作,redis中Hash在内存中的存储格式如下图:

img

  • hset(name, key, value)

    # name对应的hash中设置一个键值对(不存在,则创建;否则,修改)
     
    # 参数:
        # name,redis的name
        # key,name对应的hash中的key
        # value,name对应的hash中的value
     
    # 注:
        # hsetnx(name, key, value),当name对应的hash中不存在当前key时则创建(相当于添加)
    
  • hmset(name, mapping)

    # 在name对应的hash中批量设置键值对
     
    # 参数:
        # name,redis的name
        # mapping,字典,如:{'k1':'v1', 'k2': 'v2'}
     
    # 如:
        # r.hmset('xx', {'k1':'v1', 'k2': 'v2'})
    
  • hget(name,key)

    # 在name对应的hash中获取根据key获取value
    
  • hmget(name, keys, *args)

    # 在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')
    
  • hgetall(name)

    # 获取name对应hash的所有键值
    print(re.hgetall('xxx').get(b'name'))
    
  • hlen(name)

    # 获取name对应的hash中键值对的个数
    
  • hkeys(name)

    # 获取name对应的hash中所有的key的值
    
  • hvals(name)

    # 获取name对应的hash中所有的value的值
    
  • hexists(name, key)

    # 检查name对应的hash是否存在当前传入的key
    
  • hdel(name,*keys)

    # 将name对应的hash中指定key的键值对删除
    print(re.hdel('xxx','sex','name'))
    
  • hincrby(name, key, amount=1)

    # 自增name对应的hash中的指定key的值,不存在则创建key=amount
    # 参数:
        # name,redis中的name
        # key, hash对应的key
        # amount,自增数(整数)
    
  • hincrbyfloat(name, key, amount=1.0)

    # 自增name对应的hash中的指定key的值,不存在则创建key=amount
     
    # 参数:
        # name,redis中的name
        # key, hash对应的key
        # amount,自增数(浮点数)
     
    # 自增name对应的hash中的指定key的值,不存在则创建key=amount
    
  • hscan(name, cursor=0, match=None, count=None)

    # 增量式迭代获取,对于数据大的数据非常有用,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时,表示数据已经通过分片获取完毕
    
  • 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
    

五、Redis通用操作

所有类型都支持的操作,不指定类型

delete(*names)
exists(name)
keys(pattern='*')
expire(name,time)
rename(src, dst)
move(name, db)
randomkey()
type(name)
  • delete(*names)

    根据K删除Redis中的任意数据类型
    
  • exists(name)

    检测redis的name是否存在
    
  • keys(pattern=‘*’)

    根据模型获取redis的name
    
    更多:
    	KEYS * 匹配数据库中所有key
        KEYS h?llo 匹配 hello,hallo和hxllo等
        KEYS h*llo 匹配 hllo 和 heeeeello 等。
        KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo 
    
  • expire(name,time)

    为某个redis的某个name设置超时时间
    
  • rename(src, dst)

    对redis的name重命名为
    
  • move(name, db)

    将redis的某个值移动到指定db下
    
  • randomkey()

    随机获取一个redis的name(不删除)
    
  • type(name)

    获取name对应值的类型
    
点击查看代码
import redis

conn = redis.Redis()
# 1 delete(*names)
# conn.delete('name', 'userinfo2')
# conn.delete(['name', 'userinfo2'])  # 不能用它
# conn.delete(*['name', 'userinfo2'])  # 可以用它


# 2 exists(name)
# res=conn.exists('userinfo')
# print(res)


# 3 keys(pattern='*')
# res=conn.keys('w?e')  #  ?表示一个字符,   * 表示多个字符
# print(res)


# 4 expire(name ,time)
# conn.expire('userinfo',3)

# 5 rename(src, dst)
# conn.rename('hobby','hobby111')

# 6 move(name, db))
# conn.move('hobby111',8)
# 7 randomkey()
# res=conn.randomkey()
# print(res)
# 8 type(name)
# print(conn.type('girls'))
print(conn.type('age'))
conn.close()

六、Redis管道

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

事务的四大特性:

-原子性
-一致性
-隔离性
-持久性

redis支持事务吗

单实例才支持所谓的事务,支持事务是基于管道的

执行命令 一条一条执行
	-张三 金额:100	
    	conn.decr('zhangsan_je', 100)
    -挂了
    -李四 jine:100
    	conn.incr('lisi_je', 100)

把这两条命令,放到一个管道中,先不执行,执行excute,一次性都执行完成
conn.decr('zhangsan_je', 100)	conn.incr('李四_je',100)

如何使用

import redis
conn = redis.Redis()
p=conn.pipeline(transaction=True)
p.multi()
p.decr('zhangsan_je', 100)
# raise Exception('崩了')
p.incr('lisi_je', 100)

p.execute()
conn.close()

七、django中使用redis

  • 方式一:自定义包方案(通用的,不针对与框架,所有框架都可以用)

    # 第一步:写一个pool.py
    	import redis
        POOL = redis.ConnectionPool(max_connections=100)
    # 第二步:以后在使用的地方,直接导入使用即可
    	coon = redis.Redis(connection_pool=POOL)
        conn.incr('count')
        res = conn.get('count')
    
  • 方式二:django方案

    • 方案一:django的缓存使用redis【推荐使用】

      settings.py中配置

      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": "123",
                      }
                  }
              }
      

      在使用redis的地方:

      cache.set('count', res+1)
      

      pickle序列化后,存入的

    • 方案二:django-redis模块【第三方模块】

      from django_redis import get_redis_connection
      
      
      def test_redis(request):
          conn = get_redis_connection()
          res = print(conn.get('count'))
          return JsonResponse({'count': '今天这个接口被访问的次数为:%s' % res}, json_dumps_params={'ensure_ascii':False})
      
posted @ 2023-03-08 20:55  dear丹  阅读(32)  评论(0编辑  收藏  举报