• redis数据库-基础


    #############################################

    # redis简介:
    # redis是一个软件,对内存进行操作
    # mysql是一个软件,对硬盘进行操作,
    # 要使用redis,首先需要安装,
    # redis是c语言编写的,数据存在内存,也可以持久化,存入文件,
    # 提供多种语言的api,是一种nosql数据库,

    #############################################

    使用Redis有哪些好处?
    (1) 速度快,因为数据存在内存中,
    (2) 支持丰富数据类型,支持string,list,set,sorted set,hash
    (3) 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
    (4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

    #############################################

    Redis安装和基本使用
    1,下载:wget http://download.redis.io/releases/redis-3.0.6.tar.gz
    2,解压:tar xzf redis-3.0.6.tar.gz
    3,cd redis-3.0.6
    4,make   # 因为redis是c语言编写的所以需要进行编译
    
    启动服务端
    src/redis-server
    
    启动客户端
    src/redis-cli
    redis> set foo bar
    OK
    redis> get foo
    "bar"

    查看进程:
    ps aux | grep redis,这个命令,没有新的内容就没有启动,

    关闭进程
    sudo kill -9 进程号,这样就关闭进程了,

    ############################################

    API使用
    redis-py 的API的使用可以分类为:
    1,连接方式
    2,连接池
    3,操作  String 操作  Hash 操作  List 操作  Set 操作  Sort Set 操作
    4,管道
    5,发布订阅

    ############################################

    # Python操作Redis
    # 我们自己的电脑需要安装一个模块,
    # pip install redis
    import redis
    conn=redis.Redis(host='123.57.142.175',port=6379)
    conn.set('K12','123456')
    print(conn.get('K12'))

    #############################################

    # python-redis连接池
    # 创建连接,更加推荐使用连接池,
    
    import redis
    
    # 创建连接池,
    # max_connections这是最大连接数,刚启动是一个连接都没有,
    pool = redis.ConnectionPool(host='123.57.142.175', port=6379,max_connections=1000)
    # 去连接池中获取连接,
    conn = redis.Redis(connection_pool=pool)
    # 设置值
    conn.set('foo', 'bar')
    
    # 使用连接池注意:
    # 1,初始创建连接池,连接池内是没有连接的,
    # 2,创建第一个连接,在数据存储完成之后,这个连接并没有断,在内部有一个列表存储,
    # 3,这个时候连接池有一个连接,如果再来第二个连接,就不用再连接了,就可以拿上一个连接直接用就行了,
    # 4,如果第一个连接正在做操作,但是同时又来了第二个连接,这个时候就需要再次创建第二个连接,所以就是说两个连接够用了所有的操作,就不用去新建连接了,
    # 5,如果并发特别大的时候,还是需要新建连接的,可以设置最大1000个同时操作,
    # 6,连接池只需要创建一次,
    # 7,连接池本质就是维护一个已经和服务端连接成功的socket,
    # 8,这种连接池的思想,可以扩展,一般连接都是使用连接池,
    
    # 连接的好处:
    # 连接池的好处就是不需要每次都连接了,提高了效率,
    
    # 连接池使用
    # 使用的时候要使用单例模式,# 因为这个连接池理论上只需要创建一次就够了,剩下的就是取连接池拿连接,
    # 但是连接池在一个py文件,这个py文件运行的时候,就建立连接池了,到其他的py文件,再引入的时候,可能会重复执行
    # 最好是做一个单例模式,最简单的单例模式就是创建一个py文件,然后哪里需要去获取连接池,就把这个连接池import进来就可以了,
    # 以后操作的时候都需要使用连接池,并且要放入一个文件,做成一个单利模式,否则效率就降低了,
    # 新建一个文件:redis_pool.py,
    import redis
    pool = redis.ConnectionPool(host='192.168.100.128', port=6379, password='ji10201749', max_connections=1000)

    ############################################

    # redis三大特点
    # 1,持久化
    # 2,redis是单进程,单线程的
    # 3,5大数据类型,
    
    redis = {
        "k1":"123",  # 字符串
        "k2": [1,2,3,4],  # 列表,也叫数组,
        "k3": {1,2,3,4},  # 集合
        "k4": {"name":"andy","age":"11"},  # 字典,也叫哈希
        "k5": {("andy",79),("xiaoming",90),("xiaofang",70)},  # 有序集合
    }

    #############################################

    # redis字符串操作
    # 一个key对应一个值,这个值是string类型,
    # string类型可以接受任何类型的数据,可以是json,可以是图像,容纳可达512M
    import redis
    
    pool = redis.ConnectionPool(host='192.168.100.128', port=6379, password='ji10201749', max_connections=1000)
    conn = redis.Redis(connection_pool=pool)
    # conn.delete('k2')
    # conn.flushall()  # 清空所有的key
    # print(conn.keys())
    
    # 总结:set  get  mset  mget  append
    ###################################
    # 1,设置键值:set(name, value, ex=None, px=None, nx=False, xx=False)   ex,过期时间(秒)
    # conn.set('name','andy')  # 这样一个键值就设置好了,set 键  值
    # 这个键存在就是修改,不存在就是创建,
    # conn.set('name','andy_lee')
    # 可以设置过期时间,
    # conn.set('id',11,ex=3)
    # print(conn.get('id'))
    # 2,这是获取一个值,  get(name)
    # print(conn.get('name'))
    # 3,一次性设置多个键值,这种是mset key1 value1 key2 value2 的格式,
    # conn.mset({"str1":"111","str2":"222"})
    # print(conn.keys())
    # 4,批量获取 mget(keys, *args)
    # conn.mget('ylr', 'wupeiqi')
    #
    # conn..mget(['ylr', 'wupeiqi'])
    # 5,往一个键的值里面追加内容,这就是往a1的后面追加了123
    conn.append('name', '123')  # b'andy_lee123'
    print(conn.get('name'))

    ############################################

    # redis-字典操作
    # redis有多少个哈希槽:16384 import redis pool = redis.ConnectionPool(host='192.168.100.128', port=6379, password='ji10201749', max_connections=1000) conn = redis.Redis(connection_pool=pool) # 字典操作: """ k1 = { "name":"liqian", "age":12 } """ # 1,创建值,或者修改值,hset(name, key, value) # conn.hset('k1','name','liqian') # conn.hset('k1','age',12) # 2,批量设置键值对,把上面的两步合并成为一步,hmset(name, mapping) # conn.hmset('hh32', {'name':'andy','age':123}) # 3,获取值,hget(name,key) # val = conn.hget('k1','name') # 获取某一个key, # 4,批量获取值,hmget(name, keys, *args) # val = conn.hmget('hh32',['name','age']) # 返回一个列表:[b'andy', b'123'] # 5,获取全部值, # val = conn.hgetall('k1') # 获取全部key,value # val = conn.hgetall('hh32') # 返回一个字典,{b'name': b'andy', b'age': b'123'} # print(val) # 6,获取name对应的hash中,键值对的个数, # val = conn.hlen('hh32') # 7,获取name对应的hash中,所有的keys # val = conn.hkeys('hh32') # 8,获取name对应的hash中,所有的value # val = conn.hvals('hh32') # print(val) # 9,判断是否存在传入的键 # conn.hexists(name, key) # 10,删除:hdel(name,*keys) # conn.hdel('hash-key','k1','k3') # 11,# 自增name对应的hash中的指定key的值,不存在则创建key=amount,hincrby(name, key, amount=1) # 比如计数器,对文章的阅读量进行统计, # 这种就可以使用redis,然后比如在每天的凌晨统一更新进入数据库, # 而且redis是单进程,单线程,所有的请求过来要排队,所以也不用担心并发的问题了, # print(conn.hget('hh32','age')) # conn.hincrby('hh32','age') # 每次加1 # conn.hincrby('hh32','age',amount=2) # 每次加2 # conn.hincrby('hh32','age',amount=-1) # 每次减1 # print(conn.hget('hh32','age')) # 面试题:如果redis的k4对应的字典中有一千万数据,请打印所有数据 # result = conn.hgetall('hh32') # print(result) # 这种操作一次可能就爆栈了,这种不可取,redis取到数据之后,服务器内存服务承受,爆栈, # conn.hscan_iter('hh32',count=100) # 利用yield封装hscan创建生成器,实现分批去redis中获取数据 # 这种就是100条,100条的取, # 所以切记,不知道有多少条,一定要使用这个方法取, # 使用字典,注意事项: # 1,基本操作, # 2,慎重使用conn.hgetall(),优先使用conn.hscan_iter() # 3,可以用做计数器, """ k1 = { "id":1 "title":"XXX", "price_list":[ # 这个列表是不行的,需要把列表转换成为字符串,然后存储, {"id":1,"title":"XXX"}, {"id":1,"title":"XXX"} ] } """ # 类似上面这种结构往redis里面放,但是redis不支持多层嵌套字典的,也就是说第一层是字典,里面的都是字符串,怎么放? # 所以需要json.dumps一下,转换成字符串,然后取回来的时候json.loads一下, # redis操作的时候,

    #############################################

    # redis列表操作:
    """
    redis = {
        k1:[1,2,3,4]
    }
    """
    import redis
    
    pool = redis.ConnectionPool(host='192.168.100.128', port=6379, password='ji10201749', max_connections=1000)
    conn = redis.Redis(connection_pool=pool)
    
    # 1,添加元素,每个新的元素都添加到列表的最左边,lpush(name,values)
    conn.lpush('list1', 11)  # lpush是从左边往列表追加
    conn.lpush('list1', 22)
    # 2,添加元素,每个新的元素都添加到列表的最右边,rpush(name, values)
    conn.rpush('list1', 33)  # rpush是从右边往列表追加
    # 3,name对应的list元素的个数 llen(name)
    # conn.llen(name)
    # 4,# 在name对应的列表的某一个值前或后插入一个新值  linsert(name, where, refvalue, value))
    # 参数:
    # name,redis的name
    # where,BEFORE或AFTER
    # refvalue,标杆值,即:在它前后插入数据
    # value,要插入的数据
    
    # 5,# 对name对应的list中的某一个索引位置重新赋值  r.lset(name, index, value)
    # 参数:
    # name,redis的name
    # index,list的索引位置
    # value,要设置的值
    
    # 6,# 在name对应的list中删除指定的值,r.lrem(name, value, num)
    # 参数:
    # name,redis的name
    # value,要删除的值
    # num,  num=0,删除列表中所有的指定值;
    # num=2,从前到后,删除2个;
    # num=-2,从后向前,删除2个
    conn.lrem('list1', 11)  # 这个是删除,和pop不一样,pop是删除还会返回给你,remove直接删除了,不返回,
    
    
    # 7,# 从左边拿走一个,列表里面就会减少一个,lpop(name)
    conn.lpop('list1')
    # 8,# 从右边拿走一个,列表里面就会减少一个,
    conn.rpop('list1')
    
    # 9,根据索引获取列表元素,lindex(name, index)
    
    # 10,# 在name对应的列表分片获取数据,lrange(name, start, end)
    # 参数:
    # name,redis的name
    # start,索引的起始位置
    # end,索引结束位置
    result = conn.lrange('list1', 0, 100)
    print(result)
    
    # 11,# 在name对应的列表中移除没有在start-end索引之间的值,ltrim(name, start, end)
    # 参数:
    # name,redis的name
    # start,索引的起始位置
    # end,索引结束位置
    
    
    # 队列:就是先进先出,好像排队买东西,
    # 栈:就是后进先出,好像进电梯,
    # redis的列表,如果是从左边进,从右边取,就是一个队列,从左边进,从左边取,就是栈,
    
    # 12,将多个列表排列,按照从左到右去pop对应列表的元素,blpop(keys, timeout)
    val = conn.blpop('list1', timeout=10)  # 使用这个方法会等待,一直等到有数据,使用timeout最多等待10秒,
    # 从右向左获取数据
    val = conn.brpop('list1', timeout=10)  # 从右边取,
    # 很多地方都会用,# 比如爬虫,比如爬100个url网站,一个一个的取,
    
    # rpoplpush(列表1,列表2,)# 这是从列表1的右边取出,推到列表2的左边,
    # 基本的操作就不多说了,
    
    # 如果一个列表,有一百万数据,打印出来,怎么办?
    # 这个列表没有scan_iter 这个方法,
    # 我们定义一个:
    def list_iter(key, count=100):
        index = 0
        while True:
            data_list = conn.lrange('list1', index, index + count - 1)
            if not data_list:
                return
            index += count
    
            for item in data_list:
                yield item
    
    for item in list_iter('list', count=3):
        print(item)
    # 这就是取的时候进行遍历,
    
    # 内容详细
    # 1,列表可以左插入,右插入
    # 2,可以阻塞
    # 3,通过yield创建一个生成器可以完成一点点的获取,
    # python基础里面,装饰器,迭代器,生成器都比较绕,这就是生成器的应用,

    ############################################

    # redis集合操作 set类型:
    # 注意:
    # 1,无序集合
    # 2,每一个元素都是一个string类型,
    # 3,元素具有唯一性,不能重复,
    # 4,对于集合没有修改操作
    import redis
    pool = redis.ConnectionPool(host='192.168.100.128', port=6379, password='ji10201749', max_connections=1000)
    conn = redis.Redis(connection_pool=pool)
    
    # 1,新增,sadd(name,values)
    # conn.sadd('set1',123)
    # 一次增加多个值
    # conn.sadd('set2',12,23,34,45)
    # 2,获取,获取name对应的集合的所有成员
    # print(conn.smembers('set2'))  # 可以把a3里面所有的元素都查出来,这是无序的
    # 3,删除,
    # 删除集合里面的某一个元素
    # conn.srem('set2',12)
    # print(conn.smembers('set2'))
    # 4,从集合的右侧(尾部)移除一个成员,并将其返回,spop(name)
    
    # 5,sscan_iter(name, match=None, count=None)
    # 同字符串的操作,用于增量迭代分批获取元素,避免内存消耗太大

    #############################################

    # redis - 有序集合操作,# zset类型:
    # 1,有序集合,
    # 2,元素也是string类型,
    # 3,元素具有唯一性,不重复,
    # 4,每一个元素都会关联一个double类型的score,表示权重,通过权重将元素从小到大排序
    # 5,没有修改操作,
    import redis
    
    pool = redis.ConnectionPool(host='192.168.100.128', port=6379, password='ji10201749', max_connections=1000)
    conn = redis.Redis(connection_pool=pool)
    
    # 1,增加:zadd(name, *args, **kwargs)
    # conn.zadd("1",{'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7})
    # print(conn.keys())
    # print(conn.type('1'))
    
    # 2,照索引范围获取name对应的有序集合的元素,
    # r.zrange( name, start, end, desc=False, withscores=False, score_cast_func=float)
    # 参数:
    # name,redis的name
    # start,有序集合索引起始位置(非分数)
    # end,有序集合索引结束位置(非分数)
    # desc,排序规则,默认按照分数从小到大排序
    # withscores,是否获取元素的分数,默认只获取元素的值
    # score_cast_func,对分数进行数据转换的函数
    
    # print(conn.zrange("1",0,-1))    # 输出的结果是 ['1', '2', '3'],这个获取就是按照权值从小到大的排序的,
    
    # 3,我想要根据权值获取部分元素,如何操作? 比如我想要看权值在5 - 6的元素,
    # print(conn.zrangebyscore('1',5,6))  # 最后两个是min,max,而且都包含,
    
    # 4,查看某一个成员的权重值怎么操作? zscore(name, value)
    # print(conn.zscore('1','6'))
    
    # 5,删除指定元素,
    # conn.zrem('1','1')
    # print(conn.zrange("1",0,-1))
    
    # 6,删除权值在指定范围的元素,
    conn.zremrangebyscore('1', 5, 6)

    ############################################

    # 键命令:
    # 键命令,这个不只是针对字符串的,也针对hash,set,list,zset这些
    import redis
    
    pool = redis.ConnectionPool(host='192.168.100.128', port=6379, password='ji10201749', max_connections=1000)
    conn = redis.Redis(connection_pool=pool)
    
    # 1,获取所有的键,
    # print(conn.keys())
    # 2,这是包含a的键,
    # print(conn.keys('s*'))
    # 3,这是判断a1是否存在,存在是返回1,不存在是返回0,
    # print(conn.exists('name'))
    # 4,这是判断name这个键的值,是什么类型,
    # print(conn.type('name'))
    # 5,根据删除redis中的任意数据类型,delete(*names)
    # conn.delete('k1','name')  # 如果你没有设置过期时间,则一直存在的,直到使用del删除,
    
    # 6,这是给一个键设置过期时间,expire(name ,time)
    # conn.expire('id',3)

    #############################################

    # redis - 管道
    # redis里面类似事务的操作
    # 比如我们要在列表,集合,字典三个值里面操作,
    
    import redis
    pool = redis.ConnectionPool(host='192.168.100.128', port=6379, password='ji10201749', max_connections=1000)
    conn = redis.Redis(connection_pool=pool)
    
    # conn.set('set1',11)
    # conn.hset('hset2',"n1",666)
    # conn.lpush('list2','n2')
    # 这三个如果这样执行,就是发了三次,
    
    # 类似事务的操作:
    pipe = conn.pipeline(transaction=True)
    pipe.multi()
    pipe.set('set1', 11)
    pipe.hset('hset2', "n1", 666)
    pipe.lpush('list2', 'n2')
    pipe.execute()
    
    # 一次发送多个命令,

    ############################################

    MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据
    
    相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。redis 提供 6种数据淘汰策略:
    
    1,voltile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
    2,volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
    3,volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
    4,allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
    5,allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
    6,no-enviction(驱逐):禁止驱逐数据

    ############################################

    # 发布者和订阅者,
    # 后续再说

    #############################################

    # 主从配置
    # 集群
    # 后续再说

    ############################################

    #############################################

  • 相关阅读:
    python中的json
    vmware workstation中的NAT配置
    python内置的一些模块
    datetime
    线程池的工作过程示例
    java io read中申请读的长度与实际长度不同|RocketMQ源码
    RocketMQ集群搭建及安装rocketmq-console
    使用MAT分析JVM内存溢出
    jdbcTemplate小用总结
    Spring线程安全为何非安全,场景重现,解决安全小结
  • 原文地址:https://www.cnblogs.com/andy0816/p/12389444.html
Copyright © 2020-2023  润新知