python就业班第34天----单元测试、Redis、集群
导包:会出来个_pycache_,里面放缓存,第一次运行程序跑的慢,第二次产生缓存之后执行代码速度会变快。缓存全是二进制文件(又叫字节码文件)
测试
web程序开发过程一般包括下面几个阶段:[需求分析、设计分析、实现阶段、测试阶段]
测试的分类:
- 单元测试:对单独的代码块 ( 例如函数 ) 分别进行测试,以保证它们的正确性(由程序员完成)
- 集成测试:对大量的程序单元协同工作情况做测试
- 系统测试:同时对整个系统的正确性进行检查,而不是针对独立的片段
单元测试:经常使用的是断言 ( assert )
断言:和生活中到的语言,断定是一样的
格式:assert boolean表达式 , 异常信息
例:如果num1是整数,测试通过,否则返回异常信息,显示"num1必须是整数类型"assert isinstance(num1 , int) , "num1必须是整数类型"
isinstance:判断类型
格式:isinstance( 变量 , 数据类型)
如果变量是该数据类型,返回True,否则返回False
def divsion(num1,num2):
assert isinstance(num1,int),"num1必须是整数类型"
return num1/num2
print(divsion(10,5))
print(divsion("10",5))
搜索:
- 1.搜当前文件 ctrl + f
- 2.搜索整个项目 ctrl + shift + f
- 3.搜索指定文件目录 ctrl + shift + f 找到scope的directory
测试:
- 1.导入类unittest 的TestCase
from unittest import TestCase
- 2.编写自定义测试类,继承TestCase
class DataBaseTest(TestCase):
- 3.编写两个固定方法:setUp()和tearDown()
setUp()测试执行前执行,tearDown()出错的时候执行
测试类可以直接运行(不用写__name__入口),右键,光标放到哪个测试业务方法右键运行,执行哪个测试方法
测试业务方法必须以test开头
千万不能在同一个数据库里做测试,必须要新建
案例:测试昨天的图书馆数据库
from unittest import TestCase
from demo02library import *
# 定义类,继承自TestCase
class DataBaseTest(TestCase):
def setUp(self):
# print("setUp")
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/library16_test'
db.create_all()
def test_database_add_data(self):
# 1.创建作者对象,添加到数据库中
author = Author(name="banzhang")
db.session.add(author)
db.session.commit()
# 2.查询出来
author2 = Author.query.filter(Author.name=="banzhang").first()
# 延时方法:
import time
time.sleep(10)
# 3.断言了,作者对象一定不能为空,并且名字一定是班长
self.assertIsNotNone(author2,"author2一定不能为空")
self.assertEqual(author2.name,"name的值一定是班长")
def tearDown(self):
print("tearDown")
assertIsNotNone格式:必须写在测试类的方法里,不然找不到
from unittest import TestCase
class 类名(TestCase):
def test后缀(self):
self.assertIsNotNone(变量,"字符串")
assertIsNotNone:变量存在,则pass,不存在,测试时显示字符串
类似的还有很多,进去查看
Redis
Redis:非关系型数据库的一种
nosql介绍:一类新数据的数据库(not only sql)
泛指非关系型数据库
不支持sql语法
存储跟传统的完全不同,都是KV(keyvalue)形式,每种都有自己的api和语法,以及擅长的业务场景
nosql产品种类:MongoDB、Redis
NoSQL和SQL比较:
sql适用关系特别复杂的数据查询场景,nosql反之
sql支持事务,nosql不支持事务
虚读(幻读):看一个栏目,展开下滑到一半,去看另一个栏目,然后切回第一个栏目还能回到刚刚停留的位置
Redis简介:c语言编写,NoSQL阵营一员
Redis特效:数据存在内存(速度贼快),电脑关机时拍快照放硬盘,重启再次加载恢复;支持列表、集合、哈希等结构的存储,支持master-slave(哨兵模式)的集群
Redis安装和配置:另起文章说明
redis的logo:面包片
终端下:
查看帮助:redis-server --help
查看redis服务器进程:ps-aux|grep redis
杀死进程:kill -9 进程PID
sudo redis-server /etc/redis/redis.conf
加载指定的配置文件
启动服务端:redis-server
另开一个终端,进入客户端:redis-cli
查看redis服务器进程:ps-aux
客户端下:
运行测试,看是否能联通:ping
收到个PONG,表示连接OK
redis使用的数据库(类似mysql的use database)可以配置,默认是有16个,编号0-15,默认使用数据库0
切换到数据库10:select 10
返回个ok表示成功
增删改查:
string类型:
设置:set ; 获取:getset name zhangsan
设置name为zhangsanget name
获取name
设置存在一定的时间:setexsetex age 10 13
设置age为13,只存在10s
设置多个key和value:msetmset name zhangsan sex man height 180
get sex
字符串追加:append
set name zhangsan
append name feng
给name追加个fengget name
结果是zhangsanfengappend haha 20
要是key没有,则自动生成
获取多个:mgetmget name sex height haha
查看:keyskeys *
查看全部keys h*
查看h开头keys *x
查看x结尾keys *e*
查看包含e的
查看是否存在:existsexists name
查看name是否存在,存在返回1,不存在返回0
查看类型:typetype name
查看name的类型
删除:deldel height haha
删掉height和haha,返回的是影响的结果数
删除所有:flushall
flushall
刷新所有,所有内容都清空
设置expireexpire name 10
给name设置10秒有效期ttl name
查看name还有几秒到期,为负数就到期了
哈希类型:
redis操作hash类型
格式:hset key field value
filed:域的意思
看朋友圈滚滚滚,切出去,再切回来还能继续看
使用场景:分页缓存。跟哈希有关(类似字典、但又不一样。哈希key=>字典变量名,哈希field=>字典key)
hset person age 13
hset person name laowang
keys *
结果显示person只有一个get person
报错,要用hget过去,而且hget person
也报错,后面要加filedhget person name
hmset person name laowang age 18 sex man height 180
设置多个fieldhmget person name age sex height
获取多个fieldhkeys person
查看person里有多少个fieldhdel person name height
删除person的name和height域
list类型:类似双端队列?
左侧插入数据,格式:lpush key value1 value2 ....
lpush list 1 2 3 4
右侧插入数据:rpush ...
左侧查询数据:lrange(没有rrange)lrange list 0 3
结果为 4,3,2,1,0和3是索引
linsert list before 3 30
在3前面插入个30
linsert list after 3 300
在3后面加入个300
lrange list 0 -1
获取从后到前
lset list 2 3000
将2改为3000
删除:lrem key count value
将key域列表中,count次,值为value的删掉
count:0表示所有,正数是从头开始,负数是从尾开始,删|count|个lrem list 2 c
从头开始,删两个clrem list -3 a
从尾开始,删三个c
set类型:无序集合
set:无序,不重复sadd myset 1 2 3 7 5 8 1 2 3
设置集合,添加数据
sadd myset zhangsan lisi wangwu
smembers myset
结果:
sadd myset 1
myset添加1srem myset 7
删除myset的7
删除集合用deldel myset
zset:有序类型
权重:zaddzadd myzset 10 zhangsan 20 lisi 30 wangwu
10:zhangsan,20:lisi,30:wangwu
zrange myzset 0 -1
查看权重
zrangebyscore myzset 19 21
查看在19~21之间的
zscore myzset wangwu
推导wangwu的权重
zrem myzset zhangsan
删掉zhangsan
zrange myzset 0 -1
redis在python中使用
3个步骤:
- 1.导入redis类
- 2.创建redis对象
- 3.调用方法
例:
# 1.导入redis类
import redis
# 2.创建redis对象,decode_response=True,默认就会解码
# 形参是默认的,可以都不写,decode_response是解码,不然读出来是字节码形式
redis_store = redis.StrictRedis(host="127.0.0.1",port=6379,decode_response=True)
# 3.调用方法
# 存储数据
redis_sotre.set("name","laowang")
# 获取数据
value = redis_store.get("name")
print(value)
# 修改数据
redis_store.set("name","banzhang")
value = redis_store.get("name")
print(value)
# 删除数据
redis_store.delete("name")
value = redis_store.get("name")
print(value)
redis.StrictRedis()
按 ctrl + p查看参数,如果不写响应解码 decode_response=True
,则数据以字节码形式显示'b'laowang
集群
主从概念:一个master可以有多个slave,一个slave可以有多个slave,如此下去就是集群
主从搭建:
pass,晚点专门写另一篇文章
配置主从:
- 1.
ifconfig
查看ip - 2.修改/etc/redis/redis.conf
- 3.将127.0.0.1改成ip(bind的那行)
- 4.如果继承搭建不了,将protected-mode改为no
配置文件目录为/usr/local/redis/redis.conf(Ubuntu16是这个,18和其它的系统我就不知道了)sudo cp /usr/local/redis/redis.conf /etc/redis/
将redis.conf拷贝个,目标文件slaveof.conf(同目录,放到另一台服务器,如果没有改下端口也行)
配置slaveof,主人是谁: slave 主人ip 主人端口
启动起来,可指定配置文件:sudo redis-server redis.conf
sudo redis-server slaveof.conf
查看是否有主从:redis-cli -h ip info Relication
然后主从分离。主人负责在redis写,奴隶负责读redis-cli -h ip -p 端口
奴隶和主人都启动
主人即可写,也可以读(基本不用);奴隶只能做读
如果同时的访问量过大(1000w),主服务器肯定就会挂掉,大公司都会有很多的服务器(华东地区、华南、港澳台)
当请求来时,先由负载均衡服务器处理,把请求转发到另外的一台服务器上
负载均衡服务器:Negix
分类:
软件层面(一台电脑,靠软件启动多个redis服务),不能应付高并发
硬件层间(多台电脑,每个都启动一个或多个redis服务),可以应付高并发
集群搭建:
在conf搞下面代码port 端口号
bind ip地址
daemonize yes
// 守护进程,是否运行后台进程pidfile ??.pid
cluster -enabled yes
// 是否允许创建集群cluster -config -file
//配置文件cluster -node -timeout 15000
//超时appendonly yes
// 是否允许其他加入进来
必须三个以上,才能成为集群,不然搭建不起来
配置好6个conf后,启动服务,然后搞rbredis-trib.rb
然后创建集群:一旦创建好后,主从就会给你分配好了,会提示你要不要接受这种配置
会跳出来个有个slots,槽的意思,一个是0~16383,它计算你要搞的内容在哪个槽里面,你的在哪个槽,它就给你弄到对于的服务器
槽的算法:CRC16算法
跟python交互
from rediscluster import *
if __name__ == '__main__':
try:
# 构建所有的节点,Redis会使⽤CRC16算法,将键和值写到某个节点上
startup_nodes = [
{'host': '192.168.26.128', 'port': '7000'},
{'host': '192.168.26.130', 'port': '7003'},
{'host': '192.168.26.128', 'port': '7001'},
]
# 构建StrictRedisCluster对象
src=StrictRedisCluster(startup_nodes=startup_nodes,decode_responses=True)
# 设置键为name、值为itheima的数据
result=src.set('name','itheima')
print(result)
# 获取键为name
name = src.get('name')
print(name)
except Exception as e:
print(e)