数据库
Mysql
1. 基本概念
很多功能如果只是通过文件操作来改变数据是非常繁琐的,对于多台机器或者多个进程操作一份数据会存在安全和并发的问题
数据库是一种C/S架构的操作数据文件的一个管理软件能够解决并发问题,更加简单快速的完成数据的增删改查,拥有容错和高可用机制
数据库管理系统(DBMS)专门用来管理数据文件,帮助用户更简洁的操作数据的软件
2. 数据库的类型
关系型数据库:关联性强,一个部分信息可以获取相关全部信息 如:mysql、sql server(收费但是严谨安全性高)、oracle(开源)
非关系型数据:类似根据字典中的key和value来运行,可通过key来找calue,不能通过value找key 如:redis、mongodb
3. 数据库的操作
概念:DDL数据库定义语言(创建库、创建表)
DML数据库操作语言(存数据、删数据、改数据、查数据)
DCL数据库控制权限
3.1 mysql对用户操作
select user() --查看当前用户 set password = password('xxx') --修改密码 create user'用户名'@'IP字段'identified by'密码'; --创建一个用户属于哪个IP段 show grants for ‘用户’@‘IP段’; --查看当前用户有哪些权限 grant all on *.* to '用户'@'IP段'; --所有的(all)权限所有的库(*)所有的表(.*)给那个用户的IP段 flush privileges; --给完权限刷新后生效 grant all on *.* to '用户'@'%'identified by '密码' --授权并创建用户,同样刷新后生效
3.2 mysql库操作
create database 数据库名; --创建库 show databases; --查看当前有多少个数据库 select database(); --查看当前使用的数据库 use 数据库名; --切换到这个数据库下 drop database 数据库名; --删除库
3.3 mysql表操作
create table 表名字(字段1 字段1类型,字段2 字段2类型) --创建库表 show tables; --查案当前有多少表 rename 旧名字 to 新名字; --更改表名字 drop table 表名字; --删除表 desc 表名字; show create table 表名字; --查看表结构 show varables like '%需要查的东西%' --查看配置项
3.4 表的存储方式
1. MyISAM 5.5以下默认存储方式:存储的文件个数有表结构、表中的数据、索引
2. InnoDB 5.6以上的默认存储方式:存储的文件个数有表结构、表中的数据
支持行级锁、表级锁:row-level locking
支持事务:transactions
支持外键:froeign key
3. MEMORY 内存:存储的文件个数:表结构、增删改查很快、但是重启数据消失、容量很小
3.5 表结构修改
alter table 表名 add(字段 数据类型 约束); --添加表结构 alter table 表名 drop 字段名; --删除字段 alter table 表名 modify 字段; --修改已经存在的字段的宽度约束 alter table 表名 modify 字段1 after 字段2; --把字段1位置改到字段2后面 alter table 表名 modify 字段1 first; --把字段1放到最前面 alter table 表名 change 字段 新字段 类型 约束; --修改已经存在的字段名称、类型和约束
3.6 mysql数据操作
insert into 表名(字段名,字段名) values(值1,值2) --创建数据,所有的数据值必须和字段名一一对应 delete from 表 where 条件; --删除数据 update 表 set 字段=新值 where 条件; --修改数据 select * from 表名; --查看表中所有的数据 select 字段1,字段2 from 表名; --只查看表中的1和2字段 select distinct 字段1,字段2 from 表; --按照查出来的字段去重复 select 字段*12 from 表; --把字段的数值乘12输出,可加减乘除
4. 数据库的数据类型
4.1 字符串类型
char(字节数):浪费空间,但存储效率相对高,长度变化小
varchar(字节数):节省空间、存取效率相对低
例:create table t1(name char(5),job varchar(10));
4.2 数值类型
int(位数):整型,位数表示只显示几位,不影响输入几位数
例:create table t2(id int(3),uid int (5) unsigned) 注:unsigned表示插入的这个数据只能是正数
4.3 日期时间类型
year:年 date:年月日 time:时分秒 datetime:年月日时分秒
4.4 enum和set类型
enum:只能在其中的选项总选择一个,选择未出现的选项不打印
set:可以选择选项中的任意多个,选择其中没有的不打印
例:create tabl t3(name char(12),gender ENUM('male','female'),hobby set('抽烟','喝酒','烫头','洗脚');
5. 约束
not null:设置一个字段不能为空 create table t1(id int not null)
default:设置一个字段设置默认值 create table t2(age int default 18)
unique:设置一个字段不能出现重复(唯一) create table t3(id int unique)
auto_increment:只能设置int字段自动增加 create table t4(id int auto_increment)
primary key:设置一个字段为主键或联合主键(等同于非空且唯一) create table t5(id int primary key)
注:一张表只能设置一个主键,建议自己设置上
联合主键:设置两个以上为联合主键,任意联合主键都不唯一,但联合起来必须唯一 create table(id int,name char(5),primary key(id,name))
foreign key(字段) references 表2(字段):设置一个字段为外键,外键涉及到两张表,一张表的晚间字段值为另一张表的字段值
--员工表 create table staff( id int primary key auto_increment, age int, post_id int, foreign key (post_id) references post(pid) ) --部门表 create table post( pid int primary key, postname char(10) not null unique, phone_num char(11) )
--外键总是设置在后出现的表中
级联删除和级联更新:当设置外键的时候,更新和删除数据无法在一张表内进行,这时需要级联才可以
方法:在设置外键的后面加 on update cascade on delete cascade
6. 两张表中的数据关系
多对一:一张表中的多个数据对应另一张表中的一个数据,foreign key永远是在多的那一张表设置外键
一对一:一张表中的一个数据对应另一张表中的一个数据,在设置外键的字段后面设置unique两张表就为一对一
多对多:需要三张表,两张表之间对应的多对多关系在第三张表中存储
7. 单表查询
7.1 where语句
比较运算:>,<,=,>=,<=,!= 如:select * from 表名 where 字段>1000;
范围运算:
多选一:select * from 表 where 字段 in(条件,条件,条件)
模糊范围:
在一个数值区间:between and 如:select name from 表 where 字段 between 条件1 and 条件2
字符串的模糊查询:like 如:select * from 表 where 字段 like 'P%'(找到表中该字段以P开头的所有数据)
select * from 表 where 字段 like '%P'(找到表中该字段以P结尾的所有数据)
select * from 表 where 字段 like 'P_'(找到表中该字段以P开头一个字符串的,一个下划线表示一个字符长度)
正则匹配:regexp 如:select * from 表 where 字段 regexp 正则表达式
逻辑运算-条件拼接:与and 或or 非not
特殊:null 只能通过 is nul 和 is not null 来判断
7.2 分组聚合
分组group by:把group by后面的字段中的每一个不同的项都保留起来,并且把值这一项的所有行归为一组 如:select * from 表 group by 字段1(查询表根据字段1分组)
聚合函数:把多行的同一字段进行一些统计,最终得到一个结果
count(字段):统计这哥字段有多少项
sum(字段):统计这个字段对应的数值的和
avg(字段):统计这个字段对应的数值的平均值
min(字段):统计这个字段对应的数值的最小值
max(字段):统计这个字段对应的数值的最大值
使用分组聚合:select count/sum/avg/min/max(字段) from 表名 group by 字段;
7.3 having语句
having:利用聚合函数过滤组 如:select 字段 from 表 group by 字段 having avg(字段2)>10000(平均薪资大于1000的部门)
7.4 order by语句
order by:根据字段排序
select * from 表 order by 字段 --从小到大 select * from 表 order by 字段 desc --从大到小 select * from 表 order by 字段1,字段2 --先根据字段1排序,在字段1中相同的根据字段2排序 selext * from 表 order by 字段 limit 5; --输出字段的前5个 selext * from 表 order by 字段 limit 0/5/10,5; --输出字段从0/5/10位置开始取5个值
7.5 语句顺序
select distinct⑤ 字段 from① 表 where② group by③ having④ order by⑥ limit⑦
8. pymysql模块
import pymysql conn = pysql.connect(host='127.0.0.1',user='root',password='123',database='day40') cur = conn.cursor() #数据库的操作符,游标 cur = conn.curson(pymysql.cursors.DictCursor) #取出的为字典 cur.execute('select * from 表 where 条件') ret = cur.fechone() #拿一行 ret2 = cur.cur.fetchall() #取出所有 ret3 = cur.fetchmany(x) #取x条 print(ret,ret2,ret3) #字典:print(ret['字段']) conn.commit() #提交才能到数据库中 conn.close() #执行可能报错 try : cur.executu(sql) #执行sql语句 conn.commit() #提交到数据库 except: conn.rollback() #如果发生错误则回滚
9. 多表查询
select * from 表1,表2:两张表连在一起查,笛卡尔积式表
9.1 连表查询
inner join 内连接:两张表条件不匹配的项不会出现在结果中 如:select * from 表1 inner join 表2 on 表1.字段 = 表2.字段;
left join 左外连接:只能显示全部的左表(表1)中的数据 如:select * from 表1 left join 表2 on 表1.字段 = 表2.字段;
right join 右外连接:只能显示全部的右表(表2)中的数据 如:select * from 表1 right join 表2 on 表1.字段 = 表2.字段;
9.2 子查询
先找到一张表中的某一字段对应的id:select id from 表1 where 字段 = '查询的'
在找到领一张表与id对应的其他信息:select * from 表2 where 字段 == '查询的'
结合成子查询:select * from 表2 where 字段 = (select id from 表1 where 字段 = '查询的')
--找出年龄大于25岁的员工及员工所在的部门名称 select 表1.name from 表1 where id in (select 字段 from 表2 group by 字段 having avg(age)>25); --查看不足1人的部门名 select * from department where id not in(select dep_id from emp group by dep_id); --查询大于所有人平均年龄的员工名与年龄 select * from emp where age >(selet avg(age) from emp); --查询大于部门内平均年龄的员工名和年龄 select * from emp inner join(select dep_id,avg(age) avg_age from emp group by dep_id) as don emp.dep_id = d.dep_id where emp.age > d.avg_age;
10. 索引
10.1 概念
索引就是建立一个存储表阶段就有的一个存储结构能在查询的时候加速,主要提升查询速度
10.2 数据库的存储方式
新的数据结构:平衡树balance——b树,索引加速度,但写的速度变慢
在b树的基础山改进行了改良——b+树,分支节点的根节点都不再存储实际的数据
让分支和根节点能存储更多的索引信息就降低了输的高度
所有的实际数据都存储在叶子节点中
在叶子节点之间加入了双向的链式结构,方便查询范围条件
10.3 聚集索引和辅助索引
聚集索引是将数据直接存储在树结构的叶子节点上,相对较快 如:innodb中是聚集索引和辅助索引并存的
辅助索引时数据不直接存储在树中,找到的为数据的主键,通过再次主键查询得到数据,相对较慢 如:myisam中只有辅助索引
10.4 索引的种类
primary key:只有主键是聚焦索引,并约束非空且唯一,可使用联合主键
unique:自带辅助索引,并约束唯一,可使用联合唯一
index:辅助索引,无约束,可根据某两个关键字做联合索引
10.5 创建、删除和查询
创建索引:create index 索引名字 on 表(字段) 注:创建索引后再select查,则速度变快
删除索引:drop index 索引名 on 表(字段) 注:不删除会占用资源
查询索引:show create table 表名 注:查看表的字段和创建的索引还有表类型
10.6 联合索引
当a对abc条件进行索引时,不会对b,c进行单列的索引时会用 例:create index 索引名 on 表(字段1,字段2)
在联合索引中如果使用or条件索引就不能生效
最左前缀原则:在联合索引中,条件必须含有在创建索引的时候的第一索引列
在整个条件中,从开始出现模糊匹配的那一刻,索引就失效了
10.7 判断索引是否成立
要查询的数据的范围大:>,<, >=,<=,!=
between and
like(结果的范围大 索引不生效,如果是abc%索引生效,但是%abc索引就不生效)
如果一些内容的区分度不高,索引页不生效
索引列不能再条件中参与计算:select * from s1 where id*10 = 1000000 注:索引不成立
and:
and条件两端的内容,优先选择一个有索引的并且属性结构更好的来进行查询
两个条件都成立层能完成where条件,先完成范围小的缩小后面条件的压力
例:select * from s1 where id = 100000 and email = 'eva100000@oldboy';
or:or条件的不会进行优化,只是会根据条件从左到右依次筛选,条件中带有or的想要索引,这些条件中所有的列都是索引列
单列索引:选择一个区分度高的列建立索引,条件中的列不要参与计算,条件的范围尽量小,使用and作为条件的连接符
使用or来连接多个条件,在满足上述条件的基础上对or相关的所有列分别创建索引
其他:使用函数是索引不成立(select * from tb1 where reverse(email) = 'egon';)
类型不一致索引不成立:如果列是字符串类型,传入条件时必须用引号引起来
排序条件为索引,则select字段必须也是索引字段,否则无法命中
如:select name from s1 order by email desc; 注:不成立
select email from s1 order by email desc; 注:成立
select * from tb1 order id desc; 特殊:如果对主键排序,则还是成立
10.8 合并索引
对两个字段分别创建索引,由于sql的条件让两个索引同时生效,那么这个两个索引就成为了合并索引
10.9 执行计划
概念:如果想在执行sql之前就知道sql语句的执行情况那么就可以使用执行计划
执行计划并不会执行sql语句,会给你列出一个执行计划如果执行计划符合自己的sql的查询则执行,否则就需要修改sql语句
使用:explain+sql索引语句
关键字:possible_keys 实际索引中可能会用到的索引
key 实际会用到的索引,如果一个都没有就是没有命中
Extra 如果现实一个Using index则这个语句就是覆盖索引
10.10 覆盖索引
概念:如果我们使用索引作为条件查询,查询完毕之后不需要回表查就是覆盖索引
判断:explain+索引条件查看Extra字段是否为Using index 是则为覆盖索引
10.11 注意事项
避免使用select * 可以用count(*) 创建表时尽量使用char代替varchar 表的字段顺序固定长度的字段优先
组合索引代替多个单列索引(由于mysql中只能使用一个索引,所以经常使用多个条件查询时更适合使用组合索引)
尽量使用短索引 使用连接(join)代替子查询 连表时注意条件类型需要一致
11. 数据库的其他操作
11.1 数据库和表的备份
--在cmd中 mysqldump -uroot -p123 bd1 > 路径+名字.sql --登录mysqldump用户,把bd1备份到指定路径 mysqldump -uroot -p123 --database new_db > 路径+名字 --恢复数据 --在mysql中 sourcr 路径+文件名 --恢复数据库
11.2 事务和锁
begin: --开启事务 select * from emp where id = 1 for update; --查询id值,for update添加行锁 update 表 set 字段 = 新值 where id = 1; --完成更新 commit; --提交事务
11.3 sql注入
--表示注释掉--之后的sql语句,如果用户输入的用户名后带--输入数据库后会注释之后sql语句导致直接登录成功
如:select * from userinfo where name = 'dfds' or 1=1;-- and password = 'dsfsd'(因为1=1永久成立,所以可以跳过用户名和密码直接登陆)
解决--导致的跳过登录
import pymysql conn = pymysql.connect(host = '127.0.0.1',user = 'root',password =='123',database='day41') cur conn.cursor() username = input('>>>') password = input('>>>') sql = "select * from userinfo where name = %s and password = %s" #把字符串格式化交给cur语句做 cur.execute(sql,(username,password)) #把需要传入的内容用元组的形式传入sql语句中可以避免sql注释问题 print(cur.fetchone()) cur.close() conn.close()
12. 慢查询优化的基本步骤
1.先运行看啊看是否真的很慢,注意设置缓存(sql_no_cache)
2.where条件单表查,锁定最小返回记录表(把查询语句的where都应用到表中返回的记录数量最小的表开始查起,单表每个字段分别查询,看看那个字段区分度最高)
3.explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)
4.order by limit形式的sql语句让排序的表优先差
5.了解业务方使用场景
6.加索引是参照建索引的几大原则
7.观察结果,无效果则从头再来
MongoDB
1. 基本概念
端口号:27017
添加环境:G:\MongoDBexe/bin
启动服务器:mongod
更改数据库存放路径:mongod --dbpath="G:\data\db"
启动客户端:mongo
常用指令:show databases 查看当前服务器中的数据库
use local 切换当前使用的数据库
db 查看当前使用的数据库,代指当前数据库名
show tabales 查看当前数据库的表
db.users 创建表
mongo服务端启动,更改端口号:mongod --dbpath"G:\data\db" --port 40000
2.Mongo增加操作
语句:db.tabalename.insert({})
db.tablename.insertOne({}) 增加一条数据
db.tablename.insertMany([{name:"xxx"},{name:"sss"}])
#insert创建 db.User.insert({"name":"Parallel","age":18}) #增加一条 db.User.insertOne({"name":"World","age":18,"hobby":["唱","跳","篮球"]}) #增加多条 db.User.insertMany([{"name":"Parallel-World","age":18},{"name":"Parallel-W","age":20}])
3.Mongo查询操作
语句:db.tablename.find({}) 查找当前数据表中所有数据
db.tablename.findOne({}) 查询符合条件的第一条数据
#查询所有age=18的数据 db.User.find({"age":18}) #查询第一条age=18的数据 db.User.findOne({"age":18})
4.Mongo更改数据
语句:db.tablenameupdate({查询符合条件的数据},{$set:{修改内容}}) $set:修饰符
官方推荐:db.tablename.updateOne({查询符合条件的数据},{$set:{修改内容}}) 修改符合条件第一条数据
db.tablename.updateMany({},{}) 修改符合条件所有数据
#更新一条数据 db.User.update({"name":"P1"},{"$set":{"name":"P2"}}) #更新多条 db.User.updateMany({"name":"P2"},{$set:{"name":"P3"}}) #更新第一条 db.User.updateOne({"name":"P3"},{$set:{"name":"P4","age":19}}) #注:如果更新数据不存在,则自动覆盖
强制删除一个字段:db.User.updateOne({"name":"P4"},{$unset:{"age":19}})
5.Mongo删除操作
语法:db.tablename.deleteOne({查询条件}) 删除符合条件的第一条数据
db.tablename.deleteMany({查询条件}) 删除所有符合条件的数据
db.users.deleteMany({age:19})
#删除第一个name=P4 db.User.deleteOne({"name":"P4"}) #批量删除name为P1,P2 db.User.deleteMany({"name":{$in":["P1","P2"]}})
6.Mongo修饰符
$inc:引用增加 db.User.update({"name":"P3"},{$inc":{age":1}}) 给name=P3的数据age加1
$and:并列 db.User.find({"$and":[{"name":"P2"},{"age":18}]}) 查询name、age满足一下条件的
$or:或者 db.User.find({"$or":[{"age":20},{"age":18}]}) 查询age=20或age=18
$in:包含或者 db.User.find({"age":{"$in":[20,18]}}) 查询age或者等于20、或者等于18的
$nin:不包含 db.User.find({"age":{"$nin":[20,18]}}) 查询age不包含20或者18的
$nor:逻辑非 db.User.find({"$nor":[{"name":"P1"},{"age":{"$lt":18}}] 找到name不是P1且age大于18的
$size:个数 db.User.find({"hobby":{"$size":2}}) 找到有两项兴趣爱好的
$mod:余数查找 db.User.find({"age":{$mod":[2,1]}}) 查找年龄为奇数的
$count:统计个数 db.User.find({"Age":{"$gt":18}}).count() 统计年龄大于18的
$rename:修改与的名称 db.User.updateMany({},{"$rename":{"hobby":"like"}}) 把hobby字段名改为like
$min:小于min值不修改,大于min值修改为min值 db.class0.update({"name":Levi"},{$min:{"age":20}}) levi的age如果大于20则修改为20
$max:大于max则不修改,小于max则修改为max db.class0.update({name:"lenzer"},{$max:{“age”:20}}) 如果lenzer的age小于20则修改为20
$each:对多个值逐个进行操作 db.User.update({"name":"P1"},{$push":{"like":{"$each":["哈哈","哇哇"]}}})
$position:指定插入位置 db.User.update({"name":"P1"},{"$push":{"like":{"$each":["rap"],$position:0}}}) 查到name=P1,将rap插入到like数据0号位置
$addToSet:向数组中添加一项,但是不能添加重复的内容 db.class1.update({"name":"P5"},{$addToSet:{"score":18}})
$ISOData():生成mongo标准时间类型数据 db.User.insert({book:'累',data:ISODate("2018-07-01 13:46:43")})
$valueof():获取当前标准时间戳 db.User.insert({"name":"P7",“data”:ISODate()/valueof()}) 新增一条数据
$all:子集或者、必须是子集 db.User.find({"hobby":{"$all":["喝"]}})
如果查询_idname数据的值必须带上ObjectId的数据类型 db.User.find({"_id":ObjectId("5kjsd49wks")})
Object查询可以直接使用:对象.属性方式,作为key
{ "_id" : ObjectId("5d5135136e43be170c207370"), "name" : "alex", "like" : { "key1" : "va1", "k2" : "v2" } } #查询对象为like,属性key1等于va1的数据 db.User.find({"like.key1":"va1"})
当Array中出现了Object会自动遍历Object中的属性
{ "_id" : ObjectId("5d5135af6e43be170c207371"), "name" : "alex", "like" : [ { "b1" : "t1" }, { "b2" : "t2" } ] } #like对象会自动遍历属性为b2,并且值为t2的数据 db.User.find({"like.b2":"t2"})
数学比较符
$gt 大于 db.tablename.find({age:{"$gt":999}}) 查找age大于999 $gte 大于等于 $lt 小于 db.tablename.find({age:{"$lt":999}}) 查找age小于999 $lte 小于等于 $eq 等于 用在 '并列' '或者' 等条件中 $ne 不等于 不存在和不等于 都是 不等于 $or 或者 db.tablename.find({"$or":[{age:1000},{name:"alex"}]}) 查询name=alex 或者 age=1000 $in 包含或者 db.tablename.find({"age":{"$in":[999,1000]}}) 查询age=999或者age=1000 ,(要求同一字段) $all 子集或者(*必须是子集,决不能是超集,交集是不可查询的) db.tablename.find({"hobby":{"$all":[5,1,3]}}) 查询hobby包含[5,1,3]的数据 $and 并列 db.user.find({"$and":[{name:"alex"},{age:1000}]})
7.Mongo索引
指简历指定键值及所在文档存储位置的对照清单,使用索引可以方便我们进行快速查找,减少遍历次数提高查找效率
ensureIndex() 功能 : 创建索引 参数 : 索引域和索引选项 e.g. 根据name域创建索引 db.class0.ensureIndex({name:1}) * 1表示正序索引 -1表示逆序索引 查看集合中索引 db.collection.getIndexes() 自定义索引名称 db.collection.ensureIndex({},{name:'myIndex'}) e.g. 对age域创建索引命名ageIndex db.class0.ensureIndex({age:1},{name:'ageIndex'}) 删除索引 db.collection.dropIndex("index") 功能:删除索引 参数: 要删除的索引名称或者键值对 e.g. db.class0.dropIndex({name:1}) db.class0.dropIndex('ageIndex') db.collection.dropIndexes() 功能:删除所有索引 * _id是系统自动创建的主键索引,不能删除
8.Mongo高级函数
排序sort:db.User.find({}).sort({"age":-1}) #age从大到小排序
db.User.find({}).sort({"age":1}) #age从小到大排序
筛选limit:db.User.find({}).limit(2)
跳过skip:db.User.find({}).skip(2) 跳过前2个
#示例:分页功能实现 1排序,2跳过,3选取 page = 页码 = 1 count = 每页条目 = 2 db.users.find({}).sort({age:1}.skip((page-1)*count).limit(count)) db.users.find({}).sort({age:1}.skip(2).limit(2))
9.Python操作Mongo
#如果查询 _id 那么数据的值必须带上objectId的数据类型 res = MongoDB.User.find_one({"_id":ObjectId("5d50e7a6c66e63a1ef05889e")}) #连接数据库 from bson import ObjectId from pymongo import MongoClient MC = MongoClient("127.0.0.1",27017,)#连接数据库 MongoDB = MC["MoGo"]#选择一个库 #增加一条数据 res = MongoDB.User.insert_one({"name":"xjk","age":20}) print(res.inserted_id,type(res.inserted_id))#打印插入数据id # 增加多条数据 res = MongoDB.User.insert_many([{"name":"xjk2","age":21},{"name":"xjk3","age":22}]) #查询一条数据 res = MongoDB.User.find_one({"_id":ObjectId("5d50e7a6c66e63a1ef05889e")}) print(res) res = MongoDB.User.find({"_id":ObjectId("5d50e7a6c66e63a1ef05889e")}) print(res) #<pymongo.cursor.Cursor object at 0x000001BA6E686B00> #修改(所有age+1) MongoDB.User.update_on({},{"$inc":{"age":1}}) #删除 MongoDB.User.delete_many({}) #删除所有数据 #高级用法 #limit res = MongoDB.User.find({}).limit(1) for row in res: print(row) #skip res = MongoDB.User.find({}).skip(5) for row in res: print(row) #sort用法 from pymongo import DESCENDING,ASCENDING res = MongoDB.User.find({}).sort('age',ASCENDING)#正序 for row in res: print(row) #DESCENDING 正序 #ASCENDING 倒叙
Redis
1. 基本概念
数据默认写入到内存,如果断电或服务器宕机,redis进程挂掉数据丢失,内存性数据库
2. 安装
1.解决编译安装所需的依赖环境 yum install gcc patch libffi-devel python-devel zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel openssl openssl-devel -y
2.在目标目录下 ,下载源代码包 wget http://download.redis.io/releases/redis-4.0.10.tar.gz 解压:tar -zxvf -redis-4.0.10.tar.gz
3.执行./configure --prefix=/opt/redis/ #释放makefile,告诉gcc编译器,redis的安装路径 如果默认没有configure脚本,出现了makefile,直接make&&make install 安装即可
4.编译且安装 make && make install
5.指定配置文件,Centos安全的启动redis服务端
1.第一步 [root@xujunk safe_conf]#vim /safe_conf/redis.conf #在redis.conf配置信息如下 bind 127.0.0.1 protected-mode yes port 6379 requirepass haohaio daemonize yes pidfile /var/run/redis_6379.pid loglevel notice logfile "" 2.用自己配置好redis.conf 开启redis [root@xujunk safe_conf]#redis-server /opt/my_redis/redis-4.0.10/safe_conf/redis.conf 3.查看redis启动状态: [root@xujunk safe_conf]#ps -ef |grep redis 4.redis-cli启动,haohaiyou是密码 [root@xujunk safe_conf]#redis-cli -p 6400 -h 127.0.0.1 -a haohaiyou
6.过滤出配置文件有益的信息(取出空白行和注释行)
#找出注释行的数据 grep "^#" redis.conf #找出空行 grep "^$" #找出除空白行 和 注释行 以外的行 [root@xujunk redis-4.0.10]#grep -v "^#" redis.conf | grep -v "^$" #-v 作用取相反
7.指定配置文件启动
bind 192.168.182.130 #绑定ip,如需要远程访问,需要填写服务器ip protected-mode yes #安全模式 port 6800 #端口 requirepass haohaio #密码 daemonize yes #守护进程方式运行,后台运行 pidfile /var/run/redis_6379.pid #进程id文件 loglevel notice #日志等级 logfile "" #日志文件 slaveof #主从复制
#启动redis服务端: [root@Parallel redis-4.0.10]#redis-server redis.conf #启动redis客户端 [root@Parallel redis-4.0.10]#redis-cli -p 6379 -h 127.0.0.1 #查看redis 进程状态 ps -ef|grep redis netstat -tunlp|grep redis #LISTEN 表示监听状态 #验证连接成功 #客户端输入: 127.0.0.1:6379> ping 返回值:PONG
3.数据结构
reid是一种高级的key:value存储系统,其中balue支持物种数据类型:字符串、散列、列表、集合、有序集合
#基本命令 127.0.0.1:6379> keys * #查看所有的key 127.0.0.1:6379> type key #查看key的类型 127.0.0.1:6379> expire key seconds #过期时间 示例: >expire name "Tom" 10 #表示10秒后 {"name":"Tom"}键值对将消失 127.0.0.1:6379> ttl key #查看key过期剩余时间 -2表示key已经不存在了 127.0.0.1:6379>persist key #取消key的过期时间 -1表示key存在,没有过期时间 127.0.0.1:6379>exists key #判断key存在 存在返回1 否则0 127.0.0.1:6379>exists key #判断key存在不? 存在返回1 否则0 127.0.0.1:6379>del key #删除key 返回1代表删除成功,返回0代表删除失败 127.0.0.1:6379>dbsize #计算当前库key的数量, 没有参数
1.字符串
1.set 设置key 127.0.0.1:6379> set k1 "v1" >>>OK 2.get 获取key 127.0.0.1:6379> get k1 >>>"v1" 3.append 追加string 127.0.0.1:6379>append name ' dsb' >>> 6 #返回追加后字符串长度 4.mset 追加key的string 127.0.0.1:6379> mset u1 "xm" u2 "xg" u3 "xh" OK 5.mget 获取多个value 127.0.0.1:6379> mget u1 u2 1) "xm" 2) "xg" 6.del 删除key 127.0.0.1:6379> del k1 (integer) 1 7. incr 递增 +1 127.0.0.1:6379> incr num (integer) 10 8.decr 递减-1 127.0.0.1:6379> decr num (integer) 9
2.list类型
1.lpush 从列表左边插入 127.0.0.1:6379>lpush hobby "sleep" "swim" "read" 2.lrange 获取一定长度的元素 127.0.0.1:6379> lrange hobby 0 3 1) "read" 2) "swim" 3) "sleep" 3.rpush 从列表右边插 127.0.0.1:6379> lrange hobby 0 4 1) "read" 2) "swim" 3) "sleep" 4) "pingpang" 4.ltrim 截取一定长度列表,从索引0取到2,删除其余的元素 127.0.0.1:6379> ltrim hobby 0 2 OK 5.llen 查看长度 127.0.0.1:6379> llen hobby (integer) 3 6.lpop 删除最左边一个元素 127.0.0.1:6379> lpop hobby "read" 7.rpop 删除最右边一个元素 127.0.0.1:6379> rpop hobby "sleep" 8.lpushx/rpushx key存在添加值,不存在不处理 127.0.0.1:6379> lpushx hobby "read" (integer) 2
3.sets集合类型
一种无序的集合,集合中的元素没有先后顺序
1.sadd 添加 元素 127.0.0.1:6379> sadd zoo "tigger" (integer) 1 2.srem 删除元素 127.0.0.1:6379> srem zoo "tigger" (integer) 1 3.sismember 判断是否为set的一个元素 127.0.0.1:6379> sismember zoo "tigger" (integer) 1 4.smembers 返回集合所有的成员 127.0.0.1:6379> smembers zoo 1) "monkey" 2) "pandas" 3) "tigger" 5.sdiff 返回一个集合和其他集合的差异 127.0.0.1:6379> sdiff zoo zoo2 1) "tigger" 2) "pandas" #找出集合zoo中有的,而zoo2中没有的元素 6.sunion 返回几个集合的并集 127.0.0.1:6379> sunion zoo zoo2 1) "tigger" 2) "monkey" 3) "pandas" 4) "bird" 5) "fox"
4.有序集合类型
#利用有序集合排序,排序学生的成绩 127.0.0.1:6379> zadd score 70 "wang" (integer) 1 127.0.0.1:6379> zadd score 60 "li" (integer) 1 127.0.0.1:6379> zadd score 60 "liu" (integer) 1 #zreverange倒叙 zrange正序 127.0.0.1:6379> zrevrange score 0 -1 withscores 1) "wang" 2) "70" 3) "liu" 4) "60" 5) "li" 6) "60" 127.0.0.1:6379> zrange score 0 -1 withscores 1) "li" 2) "60" 3) "liu" 4) "60" 5) "wang" 6) "70" zrem 移除 127.0.0.1:6379> zrem score wang (integer) 1 zcard 返回有序集合基数 127.0.0.1:6379> zcard score (integer) 2 #2个基数 zscore 返回成员的score值 127.0.0.1:6379> zscore score li "60" #查询score键,li对象的值 zrank 返回有序集合中,成员的排名,默认按score,从小到大排序 127.0.0.1:6379> zrank score wang (integer) 3 #第三名 从0索引开始
5.有序集合类型
哈希结构就是 k1 -> k1 : v1 如同字典 套字典 { k1 : { k2: v2 } } ,取出v2 必须 k1,取出k2、hashes即哈希。哈希是从redis-2.0.0版本之后才有的数据结构。hashes存的是字符串和字符串值之间的映射,比如一个用户要存储其全名、姓氏、年龄等等,就很适合使用哈希。
1.hset 设置散列值 127.0.0.1:6379> hset news1 title "New1 title" (integer) 1 127.0.0.1:6379> hset news1 content "This is first news" (integer) 1 2.hget 获取散列值 127.0.0.1:6379> hget news1 content "This is first news" 127.0.0.1:6379> hget news1 title "New1 title" 3.hmset 设置多对散列表 127.0.0.1:6379> hmset news2 title "New2 title" content "This is seconde news" OK 4.hmget 获取多对散列值 127.0.0.1:6379> hmget news2 title content 1) "New2 title" 2) "This is seconde news" 5.hsetnx 如果散列已经存在,则不设置(防止覆盖key) # 1代表设置成功,0代表设置失败 127.0.0.1:6379> hsetnx news2 title "news 2" (integer) 0 127.0.0.1:6379> hsetnx news3 title "news 3" (integer) 1 6.hkeys 返回所有keys 127.0.0.1:6379> hkeys news1 1) "content" 2) "title" 7.hvals 返回所有values 127.0.0.1:6379> hvals news1 1) "This is first news" 2) "New1 title" 8.hlen 返回散列包含域(field)的数量 127.0.0.1:6379> hlen news1 (integer) 2 127.0.0.1:6379> hlen news2 (integer) 2 9.hdel 删除散列指定的域(field) 127.0.0.1:6379> hdel news1 title (integer) 1 127.0.0.1:6379> hget news1 title (nil) 10.hexists 判断是否存在 127.0.0.1:6379> hexists news1 title (integer) 0 127.0.0.1:6379> hexists news1 content (integer) 1 #0表示不存在,1表示存在
4. 发布订阅
发布订阅的命令
PUBLISH channel msg 将信息 message 发送到指定的频道 channel SUBSCRIBE channel [channel ...] 订阅频道,可以同时订阅多个频道 UNSUBSCRIBE [channel ...] 取消订阅指定的频道, 如果不指定频道,则会取消订阅所有频道 PSUBSCRIBE pattern [pattern ...] 订阅一个或多个符合给定模式的频道,每个模式以 * 作为匹配符,比如 it* 匹配所 有以 it 开头的频道( it.news 、 it.blog 、 it.tweets 等等), news.* 匹配所有 以 news. 开头的频道( news.it 、 news.global.today 等等),诸如此类 PUNSUBSCRIBE [pattern [pattern ...]] 退订指定的规则, 如果没有参数则会退订所有规则 PUBSUB subcommand [argument [argument ...]] 查看订阅与发布系统状态 注意:使用发布订阅模式实现的消息队列,当有客户端订阅channel后只能收到后续发布到该频道的消息,之前发送的不会缓存,必须Provider和Consumer同时在线。
发布订阅的实际操作
#启动两个redis-cli窗口,订阅diantai频道 #两个订阅者输入: 127.0.0.1:6379> subscribe diantai #启动一个redis-cli窗口,向频道diantai发送消息 127.0.0.1:6379> publish diantai "hello I am a boy" (integer) 2
订阅一个或者多个符合模式的频道
#窗口1:启动两个redis-cli窗口,订阅 wang*频道 127.0.0.1:6379> PSUBSCRIBE wang* Reading messages... (press Ctrl-C to quit) 1) "psubscribe" 2) "wang*" 3) (integer) 1 #窗口2:启动redis-cli窗口,均订阅wang*频道 127.0.0.1:6379> PSUBSCRIBE wang* Reading messages... (press Ctrl-C to quit) 1) "psubscribe" 2) "wang*" 3) (integer) 1 #窗口3,发布者消息 [root@xujunk ~]# redis-cli 127.0.0.1:6379> PUBLISH wangbaoqiang "jintian zhennanshou " (integer) 2 #此时窗口1和窗口2收到: 1) "pmessage" 2) "wang*" 3) "wangbaoqiang" 4) "jintian zhennanshou "