Redis

一、redis介绍和安装

1. redis 是什么

  - 数据库就是个存数据的地方:只是不同的数据库数据组织,存放形式不一样

  - mysql 关系型数据库(oracle,sqlserver,postgrasql)

  - 非关系型数据(no sql ):redis,mongodb,clickhouse,infludb,elasticsearch,hadoop。。。

    - 没有sql:没有sql语句

    - not only sql 不仅仅是sql

  - redis:一款纯内存存储的非关系型数据库(数据都在内存),速度非常快

2. redis特点

https://www.cnblogs.com/liuqingzheng/articles/9833534.html

  - redis 是一个key-value存储系统

   - 数据类型丰富,支持5大数据类型:字符串,列表,hash(字典),集合,有序集合

redis={
        k1:'123',      字符串
        k2:[1,2,3,4],   列表/数组
        k3:{1,2,3,4}     集合
        k4:{name:lqz,age:12}  字典/哈希表
        k5:{('lqz',18),('egon',33)}  有序集合
}

  - 纯内存操作

  - 可以持久化:能把内存数据,保存到硬盘上永久存储

3. redis为什么这么快

   -1.  纯内存,减少io

  - 2. 使用了 io 多路复用的epoll网络模型

  - 3. 数据操作是单线程,避免了线程间切换

    - 多客户端同时操作,不会存在并发安全问题

  -4. 安装

    - redis:最新是7,公司里5,6 用的比较多

    - redis:开源软件,免费的,但他们不支持win

      - epoll模型不支持win

    - 微软官方:基于源码修改 ---》编译成可执行文件

    - 第三方:https://github.com/tporadowski/redis/releases/

    - win:下载安装包,一路下一步

      详见:链接

      - 安装目录在环境变量中:任意路径敲:redis-server   reidis-cli 都能找到

      - 把 redis做成了服务,以后通过服务启动即可

    - win,mac:两个可执行文件:

      redis-server :等同于 mysqld
      reidis-cli :等同于mysql

5. 启动,连接

5.1 启动方式

  - 使用服务启动

    redis-server

    redis.windows-service.conf

  # 以上命令的执行和服务启动的效果是一样的

  - 使用命令启动:redis-server

5.2 连接

  redis-cli

  redis-cli -h 地址 -p 端口(默认端口:6379)

5.3 图形化客户端(Navicate)

  - resp:后来收费了

  - 连接上发现有16个库

 连接成功:

 

6. 放值

使用resp放入值

7. 取值

cmd 中连接:get key

二、python操作redis

1. python 操作Redis之普通连接

from redis import Redis

conn = Redis(host='localhost', port=6379, db=0, decode_responses=True)
# 简单测试
# res = conn.lpush('girls','刘亦菲') # 从左边插入值
res = conn.get('name')  # pyy
print(res)

conn.close()

结果:

 

 2. Redis连接池

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

import redis
from threading import Thread
from pool import POOL  # 作为模块导入,连接的都是同一个连接池


def task():
    conn = redis.Redis(connection_pool=POOL) 
    print(conn.get('name')) #字节类型
    conn.close()


if __name__ == '__main__':
    for i in range(10):
        t = Thread(target=task)
        t.start()

结果:

 

三、redis字符串类型

1. redis模块封装了很多方法---》set  get  mset---》跟命令是一一对应的

2.以后如果遇到redis这个模块没有封装的方法,直接使用:execute_command

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

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

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

eg:

import redis

conn = redis.Redis(decode_responses=True)
# 1 set(name, value, ex=None, px=None, nx=False, xx=False)
# conn.set('hobby', '游泳')
# conn.set('age', 18, ex=5)  # ex=5 s: 过期时间为5秒,5秒后Resp中的age就没了
# conn.set('age',19,px=5000) # px=5000 ms:过期时间为5秒,5秒后Resp中的age就没了
# conn.set('age', 20, nx=True)  # nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果
conn.set('age', 19, nx=True)  # 因为age已经存在,所以set操作无效,修改不了age的值
conn.close()

如图:

 结果:

2. setnx(name,value) :当name不存在时,设置值,存在则操作无效

# 2 setnx(name, value)
conn.setnx('hy', 19)  # 设置值,只有name不存在时,执行设置操作(添加),如果存在,不会修改

结果:

3. setex(name,time, value) # 设置过期时间(以秒为单位)

# 3 setex(name,time, value)
conn.setex('hy',5,18) # 将hy 的值修改为18,5秒后过期

 结果:

 5秒后:

 4. psetex(name, time_ms, value) :设置过期时间(以毫秒为单位),值不存在,就设置值,存在则修改值

# 4 psetex(name, time_ms, value)
conn.psetex('hy',5000,'hhy')

结果:

 5秒之后:

 5. mset(*args,**kwagrs):批量设置

# 5 mset(*args, **kwargs)  批量设置,一次性,设置多个值
conn.mset({'name':'hhy','age':19,'gender':''})

 结果:

 6. get(name) :获取值

# 6 get(name) #获取值
print(conn.get('name'))

结果:

7. mget(keys, *args) :批量获取

# 7 mget(keys, *args) #批量获取
print(conn.mget(['name','age','gender']))

结果:

8. getset(name, value) :等同于 get set,设置新值并获取原来的值

# 8 getset(name, value)  # 等同于  get   set
print(conn.getset('name','adc'))

结果:

9. getrange(key, start, end) :前后都是闭区间,获取子序列(根据字节获取,非字符)

# 9 getrange(key, start, end)
print(conn.getrange('name',1,2))  # 前闭后闭区间

结果:

 10. setrange(name, offset, value):修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)

# 10 setrange(name, offset, value) # offset,字符串的索引,字节(一个汉字三个字节)
conn.setrange('name',2,'ooo')

 结果:

11. strlen(name):返回name对应值的字节长度(一个汉字3个字节,一个字母1个字节)

# 11 strlen(name)
print(conn.strlen('name'))

结果:

12.incr(self, name, amount=1): 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。

# 12 incr(self, name, amount=1) # incr 和 incrby 一样
conn.incr('age',2) # 自加2,单线程,没有并发安全,数据不会错乱,天然适合计数器  计数器---》日活(日活跃用户数,只要有用户登录,就+1)

结果:

 13. incrbyfloat(self, name, amount=1.0):自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。

# 13 incrbyfloat(self, name, amount=1.0) amount,自增数(浮点型),有浮动
conn.incrbyfloat('age',1.1)

结果:

 14.decr(self, name, amount=1):自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。

# 14 decr(self, name, amount=1) # 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
conn.decr('age')

 结果:

 15. append(key, value):在redis name对应的值后面追加内容

# 15 append(key, value) # 在value的右侧加
conn.append('name','ee')

结果:

 操作比特位---》后面聊

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 对应的值中

 

四、Redis操作之List操作

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

 1. lpush(name,values):在name对应的list中添加元素,每个新的元素都添加到列表的最左边

# 1 lpush(name, values) # 从左边插入值
conn.lpush('girls','迪丽热巴'

结果:

 2. rpush(name, values) :表示从右向左操作

# 2 rpush(name, values) 表示从右向左操作
conn.rpush('girls','古力娜扎')

结果:

 3. lpushx(name, value) :只有key存在,才能追加

# 3 lpushx(name, value) 只有key存在,才能追加
conn.lpushx('girls','杨幂')
conn.lpushx('boys','yyqx') # Redis没有任何变化,因为boys不存在

结果:

 4. rpushx(name, value) 表示从右向左操作

# 4 rpushx(name, value) 表示从右向左操作 ,name值存在,才会增加值
conn.rpushx('girls','方圆')
conn.rpushx('boys','whd')

结果:

 5. llen(name):name对应的list元素的个数

# 5 llen(name) #  name对应的list元素的个数
print(conn.llen('girls'))

结果:

 Redis:

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

# 6 linsert(name, where, refvalue, value)) 在name对应的列表的某一个值前或后插入一个新值 
# refvalue:列表中的值,value:将被插入的新值,where:插在哪(前/后)
conn.linsert('girls',where='before',refvalue='刘亦菲',value='赵露思')
conn.linsert('girls',where='after',refvalue='刘亦菲',value='赵今麦')

结果:

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

# 7 r.lset(name, index, value) # 对某个索引位置的值,重新赋值
conn.lset('girls',0,'ooo')

结果:

8. r.lrem(name, num, value)

# 8 r.lrem(name, num, value) # num=0,删除列表中所有的指定值
conn.lrem('girls',1,'刘亦菲')   # 从左侧删一个,写几个就会删几个指定的值
conn.lrem('girls',-1,'刘亦菲')   # 从右侧删一个
conn.lrem('girls',0,'刘亦菲')   # 全删除

9. lpop(name)

# 9 lpop(name)
print(conn.lpop('girls'))  # 左侧弹出一个

结果:

10.rpop(name)

# 10 rpop(name) 表示从右向左操作
print(conn.rpop('girls')) # 右侧弹出

结果:

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

# 11 lindex(name, index)
print(conn.lindex('girls',0))

结果:

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

# 12 lrange(name, start, end)
print(conn.lrange('girls',1,4)) # 前后都是闭区间

结果:

补充:一次性把列表中数据都取出来

import redis

conn = redis.Redis(decode_responses=True)
# 一次性把列表中数据都取出来
print(conn.lrange('girls',0,-1)) # -1是从右开始的第一位
print(conn.lrange('girls',0,conn.llen('girls')))
conn.close()

结果:

 

五、Redis操作之Hash操作

1.hset(name, key, value) :设置hash值

# 1 hset(name, key, value) #设置hash值
conn.hset('userinfo', 'name', 'hh')
conn.hset('userinfo', 'age', '19')

结果:

 2. hmset(name, mapping) :弃用了,统一用hset

# 2 hmset(name, mapping)  弃用了,统一用hset
conn.hmset('userinfo2',{'name':'pyy',"age":33})
conn.hset('userinfo3',mapping={'name':'xxx',"age":33})

结果:

 3. hget(name,key):获取name中某个key对应的值

# 3 hget(name,key) # 获取name中某个key对应的值
print(conn.hget('userinfo','name'))

结果:

 4. hmget(name, keys, *args) :获取值

# 4 hmget(name, keys, *args) 获取值
print(conn.hmget('userinfo',['name','age']))
print(conn.hmget('userinfo','name','age'))

结果:

 5. hgetall(name):一次性取出所有name的值

# 5 hgetall(name)  # 慎用---》userinfo 对应的value值非常多,一次性拿出来,很耗时
print(conn.hgetall('userinfo'))

结果:

 6. hlen(name) 

# 6 hlen(name)
print(conn.hlen('userinfo'))

结果:

 7. hkeys(name) :取出name所有的key值

# 7 hkeys(name) 取出name所有的key值
print(conn.hkeys('userinfo'))

结果:

 8. hvals(name):取出name中所有的value值

# 8 hvals(name) 取出name中所有的value值
print(conn.hvals('userinfo'))

结果:

 9. hexists(name, key): 判断name中是否存在这个key值

# 9 hexists(name, key) 判断name中是否存在这个key值
print(conn.hexists('userinfo','hobby'))

结果:

 10. hdel(name,*keys) :删除key值

# 10 hdel(name,*keys) 删除key值
# conn.hdel('userinfo',['name','age']) # 不支持传列表
conn.hdel('userinfo','name','age')

结果:

11. hincrby(name, key, amount=1) :让name中的某个key对应的值自动加1

# 11 hincrby(name, key, amount=1) 让name中的某个key对应的值自动加1
print(conn.hget('userinfo2','age'))
conn.hincrby('userinfo2','age') 
print(conn.hget('userinfo2','age'))

结果:

 12 hincrbyfloat(name, key, amount=1.0) :让name中的某个key对应的value值增加,amount是浮点型

13. hscan(name, cursor=0, match=None, count=None) :不单独用,取出部分数据

import redis

conn = redis.Redis(decode_responses=True)
# 13 hscan(name, cursor=0, match=None, count=None)  # 不单独用,
## 造数据
for i in range(1000):
    conn.hset('hash2','egg_%s'%i,'鸡蛋%s号'%i)

# count 数字是大致的 大小,如果拿了10 ,可能是9 可能是11
res=conn.hscan('hash2',cursor=0,count=10)   # hash是无序,所以不是从egg_0开始的
print(len(res[1]))
conn.close()

 

 结果:

 14. hscan_iter(name, match=None, count=None) :替代hgetall,一次性全取出值,如果占内存很大,会有风险 , 使用hscan_iter 分批获取值,内存占用很小

import redis

conn = redis.Redis(decode_responses=True)
# 14 hscan_iter(name, match=None, count=None)  # 替代hgetall,一次性全取出值,如果占内存很大,会有风险 , 使用hscan_iter 分批获取值,内存占用很小
for item in conn.hscan_iter('hash2',count=10):
    print(item)
conn.close()

 Redis通用操作

1. delete(*names):删除对应的name

# 1. delete(*names) # 删除对应的name ----》对应的命令是:DEL(大小写都行)
conn.delete('userinfo2') # 删除userinfo2

 2. exists(name):判断name是否存在,返回值为:0/1

# 2. exists(name):判断name是否存在,返回值为:0/1
print(conn.exists('userinfo2'))

 3. keys(pattern='*'):找出pattern对应的key值,*号表示拿出所有

# 3.keys(pattern='*'):找出pattern对应的key值,*好表示拿出所有
print(conn.keys('user*'))  # 拿出到名字中带user的key值
print(conn.keys('*'))  # 拿出所有
print(conn.keys())  # 拿出所有

结果:

 4. expire(name,time):给对应的name设置过期时间,以秒为单位

# 4. expire(name ,time):给对应的name设置过期时间,以秒为单位
conn.expire('hash2',5)

5.  rename(src, dst):给已存在的key值,重新命名

# 5. rename(src, dst):给已存在的key值,重新命名
conn.rename('gender','gen')

6. move(name, db)):将name移到其他的表中,db写几就是哪个表

# 6. move(name, db)):将name移到其他的表中,db写几就是哪个表
conn.move('name',2)

结果:

 7. randomkey():随机拿出一个key

# 7. randomkey():随机取出key
print(conn.randomkey())

结果:

 8. type(name):name对应的类型

# 8. type(name):name对应的类型
print(type('name'))

结果:

 

posted @ 2023-10-16 21:32  Maverick-Lucky  阅读(19)  评论(0)    收藏  举报