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(驱逐):禁止驱逐数据

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

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

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

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

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

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

原文地址:https://www.cnblogs.com/andy0816/p/12389444.html