【MySQL-MongoDB】关系型数据库与非关系型数据库学习笔记

一、关系型数据库与非关系型数据库

1.关系型数据库—RDBMS(relational database managment system)

建立在关系模型基础上的数据库,借助于集合代数等数据概念和方法来处理数据库中的数据;
其典型的特征是含有大量的表格;

1.1 主要关系型数据库:

oracle:在以前的大型项目中使用,银行,电信等项目;
mysql:web时代使用最广泛的关系型数据库;
ms sql server: 在微软的项目中使用;
sqlite:轻量级数据库,主要应用在移动平台;

1.2 SQL—structure query language

SQL是结构化查询语言,是一种用来操作RDBMS的数据库语言,当前关系型数据库都支持使用SQL语言进行操作。

1.3 SQL语句主要分为:

DQL:数据查询语言,用于对数据进行查询,如select;
DML: 数据操作语言,对数据进行增加、修改、删除,如insert、update、delete;
TPL: 事物处理语言,对事物进行处理,包括:begin transaction、commit、rollback;
DCL: 数据控制语言,进行授权与权限回收,如grant、revoke;
DDL:数据定义语言,进行数据库、表的管理等,如create、drop;
CCL: 指针控制语言,通过控指针完成表的操作,如declare cursor;
注:SQL不区分大小写;

在这里插入图片描述

二、MySQL-关系型数据库

2.1 MySQL的基本使用

1.MySQL数据库的特点

使用C和C++编写,可移植性高;
支持多种语言和操作系统;
支持多线程,充分利用CPU;
优化SQL查询算法,有效地提高查询速度;
支持多种存储引擎;
优点:开源 免费 不要钱 使用范围广,跨平台支持性好,提供了多种语言调用的 API

2.MySQL的安装

(1)安装与启动:

安装服务器端命令: sudo apt-get install mysql-server
启动服务: sudo service mysql start
查看进程中是否存在mysql服务: ps ajx|grep mysql 或 ps aux|grep mysql
停止服务:sudo service mysql stop
重启服务: sudo service mysql restart

(2)配置:
配置文件目录为/etc/mysql/mysql.cnf
进入conf.d目录,打开mysql.cnf,发现并没有配置
进入mysql.conf.d目录,打开mysql.cnf,可以看到配置项
主要配置项如下:

bind-address表示服务器绑定的ip,默认为127.0.0.1
port表示端口,默认为3306
datadir表示数据库目录,默认为/var/lib/mysql
general_log_file表示普通日志,默认为/var/log/mysql/mysql.log
log_error表示错误日志,默认为/var/log/mysql/error.log

图形化界面客户端:navicat

命令行客户端:

安装: sudo apt-get install mysql-client
查看帮助文档: mysql --help
连接:mysql -u root -p 密码
退出: ctrl+d 或者 quit 或 exit

3.数据完整性

1.数据类型-datatype

使用原则:够用就行,尽量使用取值范围小的,而不用大的,这样可以更多的节省存储空间;
常用数据类型:

整数:int, bit
小数:decimal,decimal表示浮点数,如decimal(5,2)表示共存5位数,小数占2位;
字符串:varchar, char
char表示固定长度的字符串,如char(3),如果填充’ab’时会补一个空格为’ab ‘;
varchar表示可变长度的字符串,如varchar(3),填充’ab’时就会存储’ab’;
字符串text:表示存储大文本,当字符大于4000时推荐使用;
日期时间:date, time, datetime
枚举类型:enum
对于图片、音频、视频等文件,不存储在数据库中,而是上传到某个服务器上,然后在表中存储这个文件的保存路径;

2.约束-constraint

主键-primary key:物理上存储的顺序,必须包含唯一值,每个表有且只有一个主键;
非空-not null:此字段不允许填写空值;
唯一-unique:此字段不允许重复; 默认-default:当不填写此值时会使用默认值,如果填写时以填写为准;
外键-foreign key: foreign key(columnX) references other_tb_name(columnY)
columnX 和 columnY 的字段类型必须一致;
对关系字段进行约束,当为关系字段填写值时,会到关联的表中查询此值是否存在,如果存在则填写成功,如果不存在则填写失败,并抛出异常;
外键约束可以保证数据分有效性,但是在进行数据的curd时,都会降低数据库的性能;

4.数据库与数据表

数据库:

查看所有数据库:show databases;
使用数据库:use db_name;
查看当前使用数据库:select database();
创建数据库:create database db_name charset=utf8;
删除数据库:drop database db_name;

数据表:

查看数据库中所有表:show tables;
查看表结构:desc tb_name;
修改表名:rename table old_name to new_name;

创建表:

create table tb_name(
	column1 datatype constraint,
	column2 datatype constraint,
	column3 datatype constraint,
	...
	columnN datatype constraint,
	primary key(one or more columns)foreign key(columnX) references other_tb_name(columnY)
);
-- 例:创建学生表
create table students(
	id int unsigned primary key auto_increment not null,
	name varchar(20) default '',
	age tinyint unsigned default 0,
	height decimal(5,2),
	gender enum('男','女','中性','保密'),
	cls_id int unsigned default 0
	);

修改表字段:

添加字段:alter table tb_name add col_name datatype constraint;
修改字段-重命名版:alter table tb_name change col_name new_name datatype constraint;
修改字段-不重命名版:alter table tb_name modify col_name datatype constraint;
删除字段:alter table tb_name drop col_name;
删除表:drop table tb_name;
查看表的创建语句:show create table tb_name;

SQL文件导入:

windows中格式:source E:\directory_name\file_name.sql

5.增删改查–curd

curd—create,update,retrieve,delete

1.查询

select * from table_name
select id,name from table_name

2.增加

insert into table_name values(…),(…)
insert into table_name(name) values (…)

3.修改

update table_name set col1=value1, col2=value2 where 条件

4.删除

delete from table_name where 条件

5.导入数据

source ~/file_address/name.sql

6.备份与恢复

1.备份

mysqldump -uroot -p 数据库名 > python.sql

2.恢复

mysql -uroot -p 新数据库名 < python.sql

7.数据库设计三范式

第一范式—原子性,列不能再分成其他列
第二范式—基于第一范式,且必须有主键,其他列必须完全依赖于主键
第三范式—基于第二范式,非主键列必须直接依赖于主键

4.MySQL查询

1.准备数据

通过as起别名, 当别名中含有空格时,需要对别名加引号,使别名为一个整体

select s.id,s.name from students as s;

消除重复行

select distinct gender from students;

2.条件-where

select * from table_name where 条件

where

  • 比较运算符:

     等于: =
     大于: >
     大于等于: >=
     小于: <
     小于等于: <=
     不等于: != 或 <>
    
  • 逻辑运算符

     and, or, not
    
  • 模糊查询

     like
     % 表示任意多个字符
     _ 表示任意一个字符
     select * from students where name like '黄%' or name like  '_靖';
    
  • 范围查询

     in 表示在一个非连续的范围内
     between ... and ... 表示在一个连续的范围内
     select * from students where (id between 1 and 8) and (age in(12, 28, 35))
    
  • 空判断

     is null
     注意:null与''不同
     select * from students where height is null;
    
  • 优先级

     优先级由高到低的顺序为:小括号,not,比较运算符,逻辑运算符
     and比or先运算,如果同时出现并希望先算or,需要结合()使用
    

3.排序-order by

select * from table_name order by col1 asc|desc;

asc 升序,默认
desc 降序,需要指明

select * from students order by age (asc), height desc;

4.聚合函数-aggregation

总数—count(*)

select count(*) from students;

最大值—max(col)

select max(id) from students where gender=2;

最小值—min(col)

select min(id) from students where age=25;

求和—sum(col)

select sum(age) from students where gender=1;

平均值—avg(col)

select avg(height) from students where gender=2;

取几位小数—round()函数-用于把数值字段舍入为指定的小数位数

SELECT ROUND(column_name,decimals) FROM table_name;

5.分组-group by

group by

select gender from students group by gender;

group by + group_concat()-串连接

select gender,group_concat(name) from students group by gender;

group by + 聚合函数

select gender,avg(age) from students group by gender;

group by + having:
having 条件表达式:用来分组查询后指定一些条件来输出查询结果;
having和where一样,但having只能用于group by
where:是对from后面指定的表进行数据筛选,属于对原始数据的筛选
having:是对group by的结果进行筛选

select gender, count() from students group by gender having count()>2;

group by + with rollup
with rollup 的作用是:在最后新增一行,来记录当前列里所有记录的总和

select gender,count(*) from students group by gender with rollup;

6.分页-limit

select * from table_name limit start,count;
select * from students order by age limit 0,3;

limit M,N(M>=0) 从第M+1条开始,显示N条

7.连接查询-join

内链接:查询的结果为两个表匹配的数据
inner join

select * from students as s inner join classes as c on s.cls_id=c.id;

右连接:查询结果包含右表所有数据,左表中不存在的以null填充
right join
左连接:查询结果包含左表所有数据,右表中不存在的以null填充
left join
查询出每种商品中最贵的商品信息
把这一步产生的结果集当做一张虚表

select cate_name, max(price) as max_price,min(price) as min_price, avg(price) price,  count(*) 
from goods 
group by cate_name;
-- 将商品表和 虚表做笛卡尔积
select * from goods inner join 虚表 as goods_info;
select * from goods inner join select (cate_name, max(price) as max_price,min(price) as min_price, avg(price) price,  count(*) 
	from goods 
	group by cate_name) as goods_info;

-- 对笛卡尔积进行数据过滤
select * from goods inner join 虚表
on goods.cate_name = goods_info.cate_name and goods.price = goods_info.max_price;

select * from goods inner join (cate_name, max(price) as max_price,min(price) as min_price, avg(price) price,  count(*) 
	from goods 
	group by cate_name)
on goods.cate_name = goods_info.cate_name and goods.price = goods_info.max_price;

-- 将商品表中 分类名称 改存储为 商品分类表中的id
-- 把 goods join goods_cates on goods.cate_name = goods_cates.name当做一张表
select * from goods join goods_cates on goods.cate_name = goods_cates.name;

update 表
set 表.字段=新值

update goods join goods_cates on goods.cate_name = goods_cates.name
set goods.cate_name = goods_cates.id;


-- 在创建商品品牌表的同事 插入商品品牌的信息
create table goods_brands (
   id int unsigned primary key auto_increment,
   name varchar(40) not null) select brand_name as name from goods group by brand_name;

select * from goods join goods_cates join goods_brands 
	on goods.cate_id = goods_cates.id and goods.brand_id = goods_brands.id;

select * from goods left join goods_cates  on goods.cate_id = goods_cates.id 
left join goods_brands on goods.brand_id = goods_brands.id;

8.自关联

表中某一列关联到另一列
使用时将一个表当成多个表使用

查看所有的省级行政区信息

select * from areas where pid is null;

统计所有的省份数量

select count(*) from areas where pid is null;

查询所有的省份包含的市

select * from areas as pro inner join areas as city on pro.aid = city.pid limit 10;

查询山西省包含的市

select * from 
	areas as pro inner join areas as city  on pro.aid = city.pid 
	where pro.atitle='山西省';

查询广东省包含的市

select * from 
	areas as pro inner join areas as city  on pro.aid = city.pid 
	where pro.atitle=' 广东省';

9.子查询-subquery

在一个select语句中,嵌入另一个select语句;
标量子查询—返回结果:一行一列

select * from students where age > (select avg(age) from studnets);

列级子查询—返回结果:一列多行

select name from classes where id in (select cls_id from students);

行级子查询—返回结果:一行多列

select * from students where (height,age) = (select max(height),max(age) from students);

10.IF语句

1.if(expr1, expr2, expr3)
如果expr1是TRUE(expr1 <> 0 and expr1 <> null), 则if()的返回值为expr2, 否则返回expr3.
IF()的返回值为数字值或者字符串值,具体情况视其所在语境而定。
作为表达式的if也可以用case when来实现
例:select if(gender=‘男’, ‘男’, ‘女’) as g from students where name=‘胡歌’;
把学生性别男改成女,女改成男

update students set gender = if(gender=‘男’,‘女’,‘男’)

2.ifnull(expr1, expr2)
假如expr1不为null, 则ifnull()返回expr1, 否则返回expr2,ifnull()
等价于 SQL Server 中:isnull(expr1, expr2)

mysql中 isnull 用法:isnull(expr)判断exper是否为空,是则返回1,否则返回0

nullif(exper1,exper2):如果expr1= expr2 成立,那么返回值为NULL,否则返回值为 expr1

3.if else 作为流程控制语句使用
if实现条件判断,满足不同条件执行不同操作。

IF search_condition
THEN statement_list1
ELSEIF search_condition THEN
	statement_list2
...
ELSE statement_list3
END IF;

注意:IF作为一条语句,在END IF后需要加上分号’;’, 以表示语句结束,其他语句如CASE, LOOP等也是相同的;

– 例如,建立一个存储过程,该存储过程通过学生学号(student_no)和课程编号(course_no)查询其成绩(grade),返回成绩和成绩的等级,成绩大于90分的为A级,小于90分大于等于80分的为B级,小于80分大于等于70分的为C级,依次到E级。那么,创建存储过程的代码如下:

CREATE PROCEDURE dbname.proc_getGrade  
(stu_no varchar(20),cour_no varchar(10))  
BEGIN 
DECLARE stu_grade float 
SELECT grade into stu_grade FROM grade 
WHERE student_no=stu_no AND course_no=cour_no;  
IF stu_grade>=90 THEN 
    SELECT stu_grade,'A' 
ELSEIF stu_grade<90 AND stu_grade>=80 THEN 
    SELECT stu_grade,'B' 
ELSEIF stu_grade<80 AND stu_grade>=70 THEN 
    SELECT stu_grade,'C' 
ELSEIF stu_grade70 AND stu_grade>=60 THEN  
    SELECT stu_grade,'D'
ELSE 
    SELECT stu_grade,'E'
END IF;

11.内置函数

字符串函数

	select ascii(str)/char(数字)/concat(str1,str2,..)/length(str);
	截取:select left/right(str,len)/substring(str,pos,len)
	去除空格:select ltrim/rtrim/trim(str)
	返回一串空格:select space(n)
	替换:select replace(str,from_str,to_str)
	大小写转换:lower/upper(str)

数学函数

	绝对值:abs(n)
	求余数:mod(m,n),m%n
	不大于/不小于n的最大整数:floor/ceiling(n)
	四舍五入:round(n,d)
	次幂:pow(x,y)
	获取圆周率:PI()
	随机数:rand()

日期时间函数

	year/month/day/hour/minute/second(time)
	date_format(date,format)
	current_date()
	current_time()
	now()

12.总结

完整格式

	select distinct *
	from tb_name
	where ...
	group by ... having ...
	order by ...
	limit start,count

SQL语句执行顺序

逻辑顺序
物理顺序 – 数据库厂商 实际处理的顺序
强调: 物理顺序虽然不保证和逻辑顺序完全一致 但是保证最终数据集结果完全一致

5.SQL之case, when, then 用法

case具有两种格式,简单case函数和case搜索函数

1.简单case函数

格式说明
    case 列名
    when 条件值1 then 选择项1
    when 条件值2 then 选项2
    else 默认值 end

case sex
	when '1' then '男'
	when '2' then '女'
	else '其他' end

2.case搜索函数

格式说明
    case
    when 列名= 条件值1 then 选择项1
    when 列名=条件值2 then 选项2…
    else 默认值 end

case when sex = '1' then '男'
	 when sex = '2' then '女'
	 else '其他' end

–这两种方式,可以实现相同的功能。简单case函数的写法相对比较简洁,但是和case搜索函数相比,功能方面会有些限制,比如写判定式。
–还有一个需要注重的问题,case函数只返回第一个符合条件的值,剩下的case部分将会被自动忽略。
–比如说,下面这段sql,你永远无法的到’第二类’这个结果

case when col_1 in ('a', 'b') then '第一类'
	 when col_1 in ('a') then '第二类'
	 else '其他' end

案例1:SQL之case when then用法

6.MySQL与python交互

6.1 python中操作Mysql步骤。

1.导入pymysql的包

from pymysql import *

2.创建connection的连接对象

	conn = connec(参数列表)
		host: 连接的mysql主机,本机为:localhost
		port: 连接的mysql主机的端口,默认为3306
		database: 数据库名
		user: 连接用户名
		password: 连接密码
		charset: 通信采用的编码方式。推荐使用uft8

对象方法

close()关闭连接
commit()提交
cursor()返回Cursor对象,用于执行sql语句并获得结果

3.获取cursor游标对象

	cur = conn.cursor()

对象方法

	close()关闭游标
	execute(sql, [parameters]) 执行语句,返回受影响的行数,主要用于执行insert, update, delete语句,也可以执行create, alter, drop等语句
	fetchone()执行查询语句时,获取查询结果集的第一行数据,返回一个元组
	fetchall()执行查询时,获取结果集的所有行,一行构成一个元组,再将这些元组装入一个元组返回

对象属性

	rowcount只读属性,表示最近一次execute()执行后受影响的行数
	connection获得当前连接对象

4.执行sql语句
5.获取sql语句得到的结果
6.关闭游标
7.关闭连接

6.2 SQL注入

手动拼接sql语句会造成注入漏洞,导致信息泄漏
当输入参数含有某些特殊字符时,可能会改变sql语句,从而该表获取信息的规则,导致信息泄漏;
解决办法:参数化列表
将SQL中需要的参数,放到一个列表中作为execute的参数传入,如果参数中有特殊字符,会被转义成普通字符;

7.MySQL高级

7.1 视图

1.定义
视图就是一条select语句执行后返回的结果集,封装了对基本表的查询操作;
视图是对若干张基本表的引用,是一张虚标,查询语句执行的结果,不存储具体的数据,基本表数据发生了改变,视图也会跟着改变;

2.创建视图
一般建议以 v_ 开头

create view v_name as select语句;

3.查看视图

show tables;

4.使用视图—视图为虚标,只做查询使用

select * from v_name;

5.删除视图

drop view v_name;

6.视图demo

database: jing_dong

创建语句:

create view v_goods_info as 
select g.*, c.name 'gc name', b.name gbname from goods g 
join goods_cates c on g.cate_id = c.id 
join goods_brands b on g.brand_id = b.id;

7.视图的作用

1.提高了重用性,就像一个函数
2.对数据库重构,却不影响的程序的运行
3.提高了安全性能,可以对不同的用户
4.让数据更加清晰

7.2 事务

1.为什么要有事务
事务广泛的运用于订单系统、银行系统等多种场景,保证转账成功钱能到账,转账失败钱能退回;

2.四大特性-ACID
原子性-atomicity,一致性-consistency
隔离性-isolation,持久性-durability

  • 1.原子性—atomicity

    一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性;

  • 2.一致性—consistency

    数据库总是从一个一致性的状态转换到另一个一致性的状态。

  • 3.隔离性—isolation

    通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。

  • 4.持久性—durability

    一旦事务提交,则其所做的修改会永久保存到数据库。

3.事务命令

开启事务:begin 或 start transaction;

开启事务后执行修改命令,变更会维护到本地缓存中,而不维护到物理表中

提交事务:commit;

将缓存中的数据变更维护到物理表中

回滚事务:rollback;

放弃缓存中变更的数据
注意:

1.修改数据的命令会自动的触发事务,自动提交,包括insert、update、delete
修改为不自动提交:set autocommit = 0;
2.而在SQL语句中有手动开启事务的原因是:可以进行多次数据的修改,如果成功一起成功,否则一起会回滚到之前的数据;
3.涉及对数据库、数据表结构,不能放在事务中回滚,会自动提交;

7.3 索引

1.为什么要索引
数据量太大,创建索引,可以优化查询速度,提高查找效率

2.索引
索引是一种特殊的文件,它们包含着对数据表里所有记录的引用指针,InnoDB数据表上的索引是表空间的一个组成部分;通俗的说,数据库索引好比是一本书的目录,能加快数据库的查询速度;

3.索引的使用
查看索引:show index from tb_name;
创建索引:create index 索引名称 on tb_name(字段名称(长度))
如果指定字段是字符串,需要指定长度,建议长度与定义字段时的长度一致,字段类型如果不是字符串,可以不填写长度部分;
删除索引:drop index 索引名称 on 表名;

4.索引demo
开启运行时间监测:set profile=1;
查看执行的时间:show profiles;
查看当前操作执行时间:show profile;

5.注意
建立太多索引将会影响更新和插入的速度,因为它同样需要更新每个索引文件;
对于一个经常需要更新和插入的表格,就没有必要为一个很少使用的where字句单独建立索引了,对于比较小的表,排序开销不会很大,没有必要建立另外的索引;

7.4 账户管理

1.MySQL账户体系:
根据账户所具有的权限的不同,MySQL的账户可以分为以下几种:
服务实例级账号:,启动了一个mysqld,即为一个数据库实例;如果某用户如root,拥有服务实例级分配的权限,那么该账号就可以删除所有的数据库、连同这些库中的表
数据库级别账号:对特定数据库执行增删改查的所有操作
数据表级别账号:对特定表执行增删改查等所有操作
字段级别的权限:对某些表的特定字段进行操作
存储程序级别的账号:对存储程序进行增删改查的操作
账户的操作主要包括创建账户、删除账户、修改密码、授权权限等

2.查看所有用户
所有用户及权限信息存储在mysql数据库的user表中
查看user表结构:desc user
host表示允许访问的主机
user表示用户名
authentication_string表示密码,为加密后的值

查看所有用户:select host,user,authentication_string from user;

3.创建账户、授权
需要使用实例级账户登录后操作,以root为例
常用权限主要包括:create,alter,drop,insert,update,delete,select
如果分配所有权限,可以使用all privileges

创建账户&授权代码:

grant 权限列表 on 数据库 to ‘用户名’@‘访问主机’ identified by ‘密码’

例:创建一个laowang的账号,密码为123456,只能通过本地访问, 并且只能对jing_dong数据库中的所有表进行读操作

grant select on jing_dong.* to ‘laowang’@‘localhost’ identified by ‘123456’

创建一个laoli的账号,密码为11111,可以任意电脑进行链接访问, 并且对jing_dong数据库中的所有表拥有所有权限

grant all privileges on jing_dong.* to ‘laoli’@’%’ identified by ‘11111’

说明:
	可以操作该数据库中的所有表,方式为:jing_dong.*
	访问主机通常使用 % 表示此账户可以使用任何ip的主机访问此数据库
	访问主机可以设置成localhost或具体的ip,表示只允许本机或特定主机访问

查看用户有哪些权限:

show grants for laowang@localhost;

4.账户操作
修改权限:

grant 权限名称 on db_name to ‘账户名’@‘主机’ with grant option;

修改密码:
使用root登录,修改MySQL数据库的user表
使用password()函数进行密码加密
update user set authentication_string=password(‘新密码’) where user=‘用户名’;
注意:修改完成后需要刷新权限
flush privileges
远程登录
修改 /etc/mysql/mysql.conf.d/mysqld.cnf 文件

vim /etc/mysql/mysql.conf.d/mysqld.cnf

重启mysql

service mysql restart

在另一台ubuntu里测试

mysql -ulaowang -p123456 -h+ip地址

删除账户

方法1:drop user ‘用户名’@‘主机’
方法2:delete from user where user=‘用户名’
操作后刷新权限:flush privileges

忘记root账户密码:忘记mysql root用户密码的解决办法(skip-grant-tables)

7.5 MySQL主从

master-主 slave-从
读写分离,更安全,更高效
注意:读写分离只能解决小量数据,不适合大公司使用
主从配置注意点:

1. 在主上先开启二进制日志功能 设置 server_id  
	sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf  将配置文件中数据中的三个值改为以下三行
	# bind-address      = 127.0.0.1
	server-id       = 1
	log_bin         = /var/log/mysql/mysql-bin.log
2. 在主上
	在主上查询信息 File 和 Position数据在 从服务器配置进行操作的时候需要用到	
	GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%' identified by 'slave';
	SHOW MASTER STATUS;
	+------------------+----------+--------------+------------------+-------------------+
	| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
	+------------------+----------+--------------+------------------+-------------------+
	| mysql-bin.000002 | 21785213 |              |                  |                   |
	+------------------+----------+--------------+------------------+-------------------+
	1 row in set (0.00 sec)
	虚拟机桥接 使虚拟机和物理机在同一个网络中
	ifconfig查看虚拟机IP地址 下面一条命令会用上
3. 在从上设置
	change master to master_host='192.168.46.89', master_user='slave', 
	       master_password='slave',master_log_file='mysql-bin.000002', master_log_pos=21785213;

三、MongoDB—非关系型数据库

一个介于关系数据库和非关系数据库之间的产品
基于分布式存储的数据库
模式自由动态查询

1.MongoDB概述

优点

易扩展: 数据之间无关系,容易扩展
大数据量,高性能:数据之间无关系性,数据库结构简单
灵活的数据库模型:NoSQL无需事先为要存储的数据建立字段,随时可以储存自定义的数据格式

缺点

数据重复存储,占用空间大

MongoDB的三要素:数据库 / 集合 / 文档

2.MongoDB安装与配置

2.1 Ubuntu

apt-get安装

sudo apt-get install -y mongodb-org

参考文档
https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/

操作MongoDB服务器的后台服务:
启动mongod后台服务

sudo service mongo start

停止mongod后台服务

sudo service mongod stop

重启mongod后台服务

sudo service mongod restart

2.2 Mac系统

安装

	brew update
	brew install mongodb --with-openssl
	sudo mkdir -p /data/db
	sudo chmod 777 /data/db

操作MongoDB服务端的后台服务
启动mongodb服务

brew services start mongod

停止mongodb服务

brew service stop mongodb

2.3 Windows

选择适合版本的社区版,下载安装包
https://www.mongodb.com/download-center#community

将安装路径添加到环境变量
在系统变量path里面添加

如:D:/MongoDB/Server/bin 添加到path

创建书存储文件路径

如:mkdir c:/data/db

命令窗口运行,开两个窗口

服务端:mongod
客户端:mongo

查看帮助

客户端:mongo -help
服务端:mongod -help

查看是否启动成功

ps ef|grep mongod

3.常见数据类型

Object ID

文档id
在插入数据的时候,如果不指定文档_id字段,会自动生成ObjectID 类型的ID
ObjectID是一个12字节的十六进制数,每个字节两位,一共是24位字符串:前4个字节为当前时间戳,接下来3个字节的机器ID,接下来的2个字节是MongoDB服务进程id,最后3个字节是最简单的增量值

String

字符串,最常用,必须是有效的UTF-8

Boolean

存储一个布尔值,true或false

Integer

整数可以是32位或64位,这取决于服务器

Double

储存浮点值

Arrays

数组或列表,多个值存储到一个键

Object

用于嵌入式的文档,即一个值为一个文档

Null

存储Null值

Timestamp

时间戳,表示从1970-1-1到现在的总秒数

Date

存储当前日期或时间的Unix时间格式

4.增删改查

插入数据
db.collection_name.insert(document)

	db.stu.insert({name:'gj',gender:1})
	db.stu.insert({_id:"20170101",name:'gj',gender:1})

保存数据

db.集合名.save(document)

save与insert区别:
insert插入_id相同的数据报错
save保存_id相同的数据,是覆盖原有数据

简单查询

db.集合名.find()

更新操作

db.集合名称.update( ,,{multi: })

参数query:查询条件
参数update:更新操作符
参数multi:可选, 默认是false,表示只更新找到的第⼀条记录, 值为true表示把满⾜条件的⽂档全部更新

举例

	db.stu.update({name:'hr'},{name:'mnc'})   更新一条
	db.stu.update({name:'hr'},{$set:{name:'hys'}})    更新一条
	db.stu.update({},{$set:{gender:0}},{multi:true})   更新全部

删除操作

db.集合名.remove(, {justOne: })

5.高级查询

5.1 查询常用方法

查询多条数据

db.集合名称.find({条件⽂档})

查询一条数据

db.集合名称.findOne({条件⽂档})

结果格式化

pretty()⽅法
db.集合名称.find({条件⽂档}).pretty()

5.2 比较运算符

等于: 默认是等于判断, 没有运算符
⼩于:$lt (less than)
⼩于等于:$lte (less than equal)
⼤于:$gt (greater than)
⼤于等于:$gte
不等于:$ne

5.3 逻辑运算符

并且(and)
	在json中写多个条件即
	举例
		  查询年龄⼤于或等于18, 并且性别为true的学⽣
		  db.stu.find({age:{$gte:18},gender:true})
或者(or)
	$or: 值为一个数组, 数组中每个json元素为或的条件
	举例
		查询年龄⼤于18, 或性别为false的学⽣
		db.stu.find({$or:[{age:{$gt:18}},{gender:false}]})
并且与或混合查询
	查询年龄⼤于18或性别为女⽣, 并且家乡为大理
	db.stu.find({$or:[{age:{$gt:18}}, {gender:false}], hometown:'大理'})

5.4 范围运算符

$in 
	判断在某个范围内
	举例
		查询年龄为1820的学⽣
		db.stu.find({age:{$in:[18,20]}})
$nin
	 判断不在某个范围内
	举例
		查询年龄为不为1820的学⽣
		 db.stu.find({age:{$nin:[18, 20]}})

5.5 正则表达式

方式1:
{字段:/正则/}
在pymongo中不支持
方式2:
{字段:{ KaTeX parse error: Expected 'EOF', got '}' at position 11: regex:"正则"}̲} 举例 查询姓黄的学生 …regex:’^黄’}})

5.6 limit和skip

使用场景:分页

⽅法limit()
	⽤于读取指定数量的⽂档
	语法: db.集合名称.find().limit(NUMBER)
	查询2条学⽣信息
		db.stu.find().limit(2)
⽅法skip()
	⽤于跳过指定数量的⽂档
	语法: db.集合名称.find().skip(NUMBER)
	跳过两个学生,查询后面的
		db.stu,skip(2)
混合使用
	查询学生信息跳过3个学生, 再查询2个学生
	 db.stu.find().limit(2).skip(3)
	db.stu.find().skip(3).limit(2)
		推荐

5.7 自定义查询

说明: 在pymongo中使用自定义查询速度很慢, 比直接遍历都要慢很多

使⽤$where后⾯写⼀个函数, 返回满⾜条件的数据
查询年龄⼤于30的学⽣
	db.stu.find({$where:function(){ return this.age > 30;}})

5.8 投影

在查询到的返回结果中, 只选择必要的字段

格式
	db.集合名称.find({},{字段名称:1,...})
	参数为字段与值, 值为1表示显示, 值为0不显示, 普通字段不写就是不显示
	注意
		 对于_id列默认是显示的, 如果不显示需要明确设置为0, 其他字段不显示不写即可

5.9 排序

⽅法sort(), ⽤于对 集进⾏排序

语法: db.集合名称.find().sort({字段:1,...})
字段后参数说明
	参数1为升序排列
	参数-1为降序排列
举例
	查询所有学生,按年龄升序
		db.stu.find().sort({age:1})
	查询所有学生,按年龄降序
		 db.stu.find().sort({age:-1})
	查询所有学生先根据性别降序, 再根据年龄升序
		db.stu.find().sort({gender:-1, age:1})

5.10 统计个数

⽅法count(): ⽤于统计结果集中⽂档条数

语法
	db.集合名称.find({条件}).count()
	db.集合名称.count({条件})
		推荐
举例
	查询男生的个数
		 db.stu.find({gender:true}).count()
		db.stu.count({gender:true})
	统计年龄大于20的男生的个数
		db.stu.count({age:{$gt:20}, gender:true})

5.11 去重

⽅法distinct():对数据进⾏去重

语法
	db.集合名称.distinct('去重字段',{条件})
举例:
	查询学生的家乡,不能重复
		db.stu.distinct('hometown')
	查询年龄大于20的学生的家乡, 不能重复
		db.stu.distinct('hometown', {age:{$gt:20}})

6.管道与聚合

6.1 分组

$group
格式
	db.集合.aggregate(
    	{$group: {_id:'$分组字段名', 显示字段:{$统计函数: '$统计字段'}}},
  )
举例
	统计男生,女生各是多少
	db.stu.aggregate(
  	{$group:{_id:'$gender', count:{$sum:1}}}
)
将整个文档为一组, 指定 id 为 null
举例
	求学生的总人数和平均年龄
	db.stu.aggregate(
  	{$group:{_id:null, count:{$sum:1}, avg_scroe:{$avg:'$age'}}}
)
透视数据: $push统计函数
	$push: 把不同内容,放入一个数组(列表)
	举例
		统计不同性别的学生姓名
		db.stu.aggregate(
  	{$group:{_id:'$gender', name:{$push:'$name'}}}
)
	使用: $$ROOT把这个文档内容加入到结果集中

6.2 过滤:

$match
作用
	用于过滤数据,只输出符合条件的才作为输出
与find的区别
	$match可以把过滤后的文档,交给下一个管道,而find()不可以
特点:
	过滤字段字段作为键, 直接写, 不能使用 '$字段名'的形式
格式
	
	db.集合.aggregate(
    {$match:{json格式过滤条件}},
	)

举例
	查询年龄大于20的学生
		  db.stu.aggregate(
  		{$match:{age:{$gt:20}}}
	)
	查询年龄大于20的男生与女生人数
		  db.stu.aggregate(
  	{$match:{age:{$gt:20}}},
  	{$group:{_id:'$gender',counter:{$sum:1}}}
	)

6.3 修改文档结构

$project
作用
	修改输入文档结构, 添加字段,删除字段,重命名字段
格式
	  db.stu.aggregate(
  	{$project:{_id:0, 字段名:1, 字典名: 1}}
)
举例
	查询 只显示学生的姓名,年龄
		db.stu.aggregate({$project:{_id:0, name:1, age:1}})
	查询男生,女生人数, 只输出性别和人数
		db.stu.aggregate(
  	{$group:{_id:'$gender', count:{$sum:1}}},
  	{$project:{_id:0,gender:'$_id', count:1}}
)

6.4 排序

$sort
作用
	将输入的文档排序后输出
格式
	db.stu.aggregate(
	 {$sort:{字段:1}}
)
		1为升序, -1为降序
举例
	查询学生信息, 按年龄升序排列
		db.stu.aggregate(
  		{$sort:{age:1}}
)
	查询男生和女生人数, 按人数降序排
		db.stu.aggregate(
   {$group:{_id:'$gender', count:{$sum:1}}},
   {$project:{_id:0,gender:'$_id', count:1}},
   {$sort:{count:-1}}
)

6.5 $skip 与 $limit

$skip: 跳过指定数量的的文档,并返回剩余文档
举例
	查询从第3条开始的学生信息

	db.stu.aggregate({$skip:2})
$limit: 限制聚合管道返回的文档数量
举例
	查询2条学生信息
		db.stu.aggregate({$limit:2})
	统计男生,女生人数, 按人数升序, 取出第二条数据
		db.stu.aggregate(
   {$group:{_id:'$gender', count:{$sum:1}}},
   {$sort:{count:1}},
   {$skip:1},
   {$limit:1}
)

6.6 $unwind

作用
	将⽂档中的某⼀个数组类型字段拆分成多条, 每条包含数组中的⼀个值
格式
	db.集合名称.aggregate({$unwind:'$字段名称'})
举例
	数据
		    db.t3.insert({_id:1,item:'t-shirt',size:['S','M','L']})
	$unwind 将集合拆分
		db.t3.aggregate({$unwind:'$size'})
	结果
		 { "_id" : 1, "item" : "t-shirt", "size" : "S" }
		  { "_id" : 1, "item" : "t-shirt", "size" : "M" }
		  { "_id" : 1, "item" : "t-shirt", "size" : "L" }
注意
	问题: 在使用$unwind的时候, 默认会丢弃属性值为空的文档.
	解决:
		如果希望保留,需要把设置 preserveNullAndEmptyArrays 为true
	格式
		  db.集合名.aggregate([
  		{$unwind:{
       path:'$字段名称'
       preserveNullAndEmptyArrays:true(保留)/false(丢弃)
    }
		])

7.pymongo

安装

pip install pymongo

导入客户端对象

from pymongo import MongoClient

链接MongoDB服务器

client = MongoClient(‘ip’, 端口号)
client = MongoClient()
如果是本地的服务器, 端口可以省略

获取集合对象

collection = client[‘数据库名’][‘集合名’]

插入一条文档:collection.insert_one({})
插入多条文档: collection.insert_many([{}, …])

删除一条文档:collection.delete_one({条件})
删除满足条件的所有文档:collection.delete_many({条件})

> 修改一条文档:collection.update_one({条件}, {
   
   "$set": {修改内容}})
> 修改满足条件的所有文档:collection.update_many({条件}, {
   
   "$set":{修改内容}})

-- 查找满足条件的一条数据,返回一个字典
data = collection.find_one({条件})
-- 查找满足条件的所有数据,返回一个游标对象,可以遍历获取对应字典数据
cursor = collection.find({})

猜你喜欢

转载自blog.csdn.net/Artificial_idiots/article/details/122968791