数据库概念:是以⼀定格式进⾏组织的数据的集合(具有特殊格式 的数据⽂件的集合。)
数据库的作用:存储数据
数据库的特点:
持久化存储
读写速度极高
保证数据的有效性
对程序支持性非常好,容易扩展
数据库的分类: 关系型数据库 和 非关系型数据库
关系型数据库(RDBMS):
是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据,本质上使用一张 二维表 来表示关系。关系型数据库的主要产品:MySQL 、 Oracle(银行、电信)、 SQLite (轻量级数据库,移动平台)、Microsoft SQL Server(微软)
非关系型数据库:
又称为NoSQL(Not Only SQL),强调Key-Value存储和文档数据库的优点。非关系型数据库的主要产品:mongoDB 、 redis
数据库管理系统(DBMS): 管理数据库,包括以下三部分:
数据库客户端通过SQL语句告诉服务器,客户端想要做什么;服务器端和数据文件一般都在同一台机器上,直接可以读写数据文件。
SQL(Structured Query Language)结构化查询语言:
SQL语句的作用是实现数据库客户端和服务端之间的通信,它是一种用来操作RDBMS的数据库语言。
SQL语句主要分为:
关系型数据库中核⼼元素:
所以pipeline为:创建数据库,在数据库中创建表,向表中添加记录
服务器端:一般服务器已经安装好了,需要管理员权限sudo apt-get install mysql-server
,一般也是启动服务的sudo service mysql start
,我们只需要用命令查看一下进程中是否存在mysql服务ps -ajx |grep mysql
,-a 显示所有用户进程 -j 任务格式显示进程 -x 显示无控制终端进程
客户端:图形化界⾯客户端navicat,linux安装很多教程,主要是下载一个可靠的.tar软件
linux 连接不上 可以转战windows(MySQL + navicat)安装教程参考:MySQL + navicat破解
数据库完整性约束⽤于保证数据的正确性。
关系模型中有四类完整性约束:实体完整性、域完整性、参照完整性和用户定义完整性
用于保证操作的数据(记录)非空、唯一且不重复。即实体完整性要求每个关系表有且仅有一个主键,每个主键值必须唯一,而且不允许为“空”或重复。
主键索引,不重复不可以为空
唯一索引,不重复可以为空
指数据库表中的 列必须满足某种特定的数据类型或约束。如 default 、 not null定义都属于域完整性的范畴。
属于表间规则。如删除父表的某记录后,子表的相应记录也应该删除。foreign key
是对数据表中字段属性的约束,用户定义完整性规则也称域完整性规则,
MySQL中定义数据字段的类型对数据库的优化是很重要的。选择合适的数据类型保存数据,好处:1.节省存储空间 2.提升查找效率
应⽤场景:
保存⼈的年龄(1-100) :tinyint
保存某个状态值(0、1):tinyint
⼩型项⽬的编号:int
float(M,D) ,只保证6位有效数字的准确性
double(M,D),只保证16位有效数字的准确性
M 代表总数字的位数,最大值是255;D代表其中小数的位数。
decimal(M,D),M 代表总的数字位数,D代表其中的小数位
应用场景: 用在需要精确的小数时,比如价格。
char 和 varchar 的区别:
char:定长字符串,指的是在创建表时,char字段占⽤硬盘空间的⼤⼩就已经固定了。
varchar:变长字符串,指的是字段占⽤硬盘空间的⼤⼩并不是固定的,⽽是由内容决定的, 等于内容的⻓度+1个字节(字符串结束’\0’)。
text:与char和varchar不同的是,text不可以有默认值,其最⼤⻓度是2的16次⽅-1
选择字符串类型的原则
经常变化的字段⽤varchar
知道固定⻓度的⽤char
尽量⽤varchar
超过255字符的只能⽤varchar或者text
能⽤varchar的地⽅不⽤text
枚举类型enum,在定义字段时就预告规定好固定的⼏个值,然后插⼊记录时值只能这⼏个固定好 的值中选择⼀个。
如:day enum(‘星期一’,‘星期二’,‘星期三’,‘星期四’,‘星期五’,‘星期六’,‘星期日’)
应用场景:当值是⼏个固定可选时,⽐如:性别、星期、⽉份、表示状态时(⽐如:是、否)
首先确保已经启动mysql服务:net start mysql
(以管理员身份运行)
打开终端,运行命令:mysql -uroot -p
,回车后输入密码即可连接成功。
因此以下语法是在mysql版本为8.0.21下执行
退出登录:
quit 和 exit
数据库操作:
查看所有数据库:show databases;
查看当前使用的数据库:select database();
创建数据库:create database 数据库名 charset=utf8;
使用数据库:use 数据库名;
删除数据库:drop database 数据库名;
退出备份(导出):mysqldump -uroot -p 数据库名 > python.sql ;
创建数据库并恢复(导入):mysql -uroot -p 新数据库名 < python.sql ;
创建学生表:
create table students(
id int unsigned primary key auto_increment not null,
name varchar(20) not null,
age tinyint unsigned default 0,
height decimal(5,2),
gender enum(“男”,"女 ",“妖”)
cls_id int unsigned default 0
);
查看当前数据库中所有表:show tables;
查看表结构:desc 表名;
重命名表的名称:rename table 原表名 to 新表名;
添加字段:alter table 表名 add 列名 类型;
如: alter table students add birthday datetime;
重命名字段:alter table 表名 change 原名 新名 类型及约束;
如: alter table students change birthday birth datetime not null;
修改字段类型:alter table 表名 modify 列名 类型及约束;
如: alter table students modify birthday date ;
删除字段:alter table 表名 drop 列名;
如: alter table students drop birthday ;
删除表:drop table 表名 ;
如: drop table students;
# 查询所有列
select * from 表名;
例:select * from classes;
# 查询指定列
select 列1,列2,....from 表名;
列:select id, name from classes;
# 定条件查询
select * from classes where id=2;
# 使用as为字段指定别名 (或者给表起别名)
select id as '编号',name as '姓名' from classes;
# 消除重复行(distinct)
select distinct gender from students;
优先级由⾼到低的顺序为:
⼩括号,not,⽐较运算符,逻辑运算符 and⽐or先运算,如果同时出现并希望先算or,需要结合()使⽤
# 查询姓名是“⻩蓉”的学⽣
select * from students where name = " ⻩蓉 ";
# 查询年龄大于等于18岁的学生
select * from students where age >= 18;
and or not
# 18岁以上的女性
select * from students where age > 18 and gender = '女';
# 查询年龄大于等于18岁的学生
select * from students where age >= 18;
% 表示多个任意字符
_ 表示一个任意字符
# 查询姓名中有 “小” 所有的名字
select * from students where name like '%小%';
# 查询姓名中 姓 “刘” 所有的名字
select * from students where name like '刘%';
# 查询有2个字的名字
select * from students where name like'__';
范围查询分为连续范围查询和⾮连续范围查询
in 表示在⼀个⾮连续的范围内(相当于多个值的or 关系) not in不在
between … and …表示在⼀个连续的范围内(是一种and关系) not between
# 查询 编号是1或3或8的学生
select * from students where id in(1,3,8)';
# 查询年龄在18到25之间的学生
select * from students where age>=18 and age<=25; 等价(where age between 18 and 25)
# 查询 没有填写身高的学生(也就是为Null)
select * from students where height is null;
# 查询填写了身⾼的男⽣
select * from students where gender='男' and height is not null;
# 查询年龄为18到35之间的男性,按照年龄从小的到大排序
select * from students where gender='男' and age between 18 and 35 order by age asc;
# 查询年龄在18到24之间的女性,身高从高到矮排序,如果身高相同的情况下按照年龄从大到小排序
select * from students where gender= '女' and age between 18 and 24 order by height desc,age desc;
# 查询学生总数
select count(*) form students;
# 查询男生有多少人
select count(*) form students where gender= '男';
# 查询最大的年龄
select max(age) from students;
# 计算所有人的年龄总和
select sum(age) from students;
# 计算所有人的年龄的平均值
select round(avg(age),2) from students;# round(数值,保留的小数位数)四舍五入
select 后的字段只能出现以下两种情况:
# 计算每种性别中的人数
select gender,count(*) from students group by gender;
# 查询每种性别中年龄的平均值
select gender,avg(age) from students group by gender;
#查询男女性别中年龄的最大值
select gender,max(age) from students where gender='男' or gender='女' group by gender;
group by + group_concat()
group_concat(字段名)根据分组结果,使⽤group_concat()来放置每⼀个分组中某字段的集合(统计每个分组某字段值的集合)
# 查询每种性别的姓名
select gender,group_concat(name) from students group by gender;
group by + having()
过滤分组结果,having作⽤和where类似,但having只能⽤于group by ⽽where是⽤来过滤表数据
# 查询平均年龄超过30岁的性别、以及名字
select gender,avg(age),group_concat(name) from students group by gender having avg(age) > 30;
# 查询每种性别中的人数多于2的性别和名字
select gender,count(*) c ,group_concat(name) from students group by gender having c >2;
group by + with rollup
with rollup的作⽤是:在最后新增⼀⾏,来记录当前表中该字段对应的操作结果,⼀般是汇总结 果
# 全列插入
insert into 表名 values (...);
insert into classes values(0,"python23",55);
# 部分列插入
insert into 表名 (列1,...) values(值1,...);
insert into classes(id,num) values(0,15);
# 全列多行插入
insert into 表名 values(...),(...)...;
insert into classes values(0,"python23",55),(0,"python24",57),(0,"python25",59);
# 部分列多⾏插⼊
insert into 表名(列1,...) values(值1,...),(值1,...)...;
insert into classes(id,num) values(0,15),(0,33),(0,22);
注:主键列是⾃动增⻓,但是在全列插⼊时需要占位,通常使⽤空值(0或者null) ; 字段默认值 default 来占位,插⼊成功后以实际数据为准
update 表名 set 列1=值1,列2=值2....where 条件
update classes set name="python78",num=55 where id=2;
delete from 表名 where 条件
delete from classes where id=2;
可以使⽤limit限制取出记录的数量,但 limit 要写在sql语句的最后。
语法: limit 起始记录,记录数(起始记录是指从第几条记录开始取,第一条记录的下标是0,默认是从0开始)
#从下标为5的记录开始取 2 条数据
select * from students limit 5,2;
# 一般取最新的记录(倒序)
select * from students order by id desc limit 0,2;
标准的SQL书写格式: select 字段1,字段1,.... from 表名 [where 条件] [group by 字段名] [order by 字段名 排序规则] [having 条件] [limit 起始位置,数量]
使用limit控制每页显示多少数据
当查询结果的列来源于多张表时,需要将多张表连接成⼀个⼤的数据集进⾏汇总显 示。
注意: 能够使⽤连接的前提是 多表之间有字段上的关联。
语法:select * from 表1 inner或left或right join 表2 where(on) 表1.列 运算符 表2.列
内连接查询
查询的结果为两个表匹配到的数据,默认是笛卡尔积
# 查询对应班级的学生以及班级信息
select * from students inner join classes where students.cls_id = classes.id;
# 按照要求显示姓名和课程名称
select students.name, classes.name from students inner join classes where students.cls_id = classes.id;
#将上一条语句起别名
select s.name,c.name from students s inner join classes c where s.cls_id = c.id;
#也可以这样写
select s.name, c.name from students s,classes c where s.cls_id = c.id;
自连接
表中的某一列,关联了这个表中的另外一列,如某个市属于某个县,一种特殊的内连接。
# 创建areas表(省没有所属的省份,,填null;城市所属的省份pid,填写省对应的编号id;)
creat table areas(
aid int primary key,
atitle varchar(20),
pid int
);
# 从sql文件中导入数据
source areas.sql;
#查询一共有多少个省
select count(*) from areas where pid is null;
# 查询省的名称为“山西省”的所有城市
select * from areas city inner join areas provice on city.pid= provice.aid where provice.atitle='山西省';
右(外)连接查询
查询的结果为两个表匹配到的数据和右表特有的数据,对于左表中不存在的数据使⽤null填充
左(外)连接查询
查询的结果为两个表匹配到的数据和左表特有的数据,对于右表中不存在的数据使⽤null填充
子查询
分类:
标量子查询: 返回的结果是一个数据(一行一列)
列子查询: 返回的结构是一列(一列多行)
行子查询:返回的结构是一行(一行多列)
#查询出高于平均升高的信息
select * from students where height > (select avg(height) from students);
# 查询学生的班级号对应于学生的学号id
select * from students where id in (select id from classes);
解决的问题:goods表不再存储分类的名称,改为分类的id
#第一步,创建goods_cates表
creat table goods_cates(
id int unsigned primary key auto_increment,
name varchar(40) not null
);
#将good表中的cate_name 插入
insert into goods_cate(name) (select cate_name from goods group by cate_name);
# 更新goods表 cate_name 为 goods_cates.id
update goods inner join goods_cate where goods.cate_name=goods_cates.name set goods.cate_name=goods.id;
# 修改cate_name 为cate_id
alter table goods change cate_name cate_id int unsinged not null;
一个表的主键在另外一个表中出现,在另外一个表中称为外键。
作用: 表间的数据插入、更新的时候的一种约束
创建外键:
alter table goods add foreign key(cate_id) references goods_cates(id);
create table goods_test(
id int primary key auto_increment,
name varchar(150) not null,
cate_id int unsigned not null,
brand_id int unsigned not null,
foreign key (cate_id) references goods_cates(id),
foreign key (brand_id) references goods_brands(id)
);
取消外键约束:
alter table goods_test drop foreign key 外键名
视图: 是把复杂SQL语句的功能封装起来的一个虚表,数据来自于各实际存在的表,仅仅支持查询,
视图是对若干基本表的引用,一张虚表,只查询语句执行结果的字段类型和约束,不存储具体的数据(基本表数据发生了改变,视图也会跟着改变)
作用: ⽅便操作,特别是查询操作,减少复杂的SQL语句,增强可读性;
创建视图: create view 视图名 as select 语句;
(视图名建议以v_开头)
查看视图: show tables;
使用视图: 视图的用途就是查询 select * from v_goods_info;
删除视图: drop view 视图名称
是指 作为一个基本工作单元执行的一些列SQL语句的操作,要么完全地执行,要么完全地不执行
事物的四大特性ACID:
原子性(Atomicity):
⼀个事务必须被视为⼀个不可分割的最⼩⼯作单元,整个事务中的所有操作要么全部提交成功, 要么全部失败回滚,对于⼀个事务来说,不可能只执⾏其中的⼀部分操作,这就是事务的原⼦性
一致性(Consistency)
(加500减也是500)数据库总是从⼀个⼀致性的状态转换到另⼀个⼀致性的状态。
隔离性(Isolation)
通常来说,⼀个事务所做的修改在最终提交以前,对其他事务是不可⻅的。
持久性(Durability)
⼀旦事务提交,则其所做的修改会永久保存到数据库。
原⼦性强调事务中的多个操作时⼀个整体
⼀致性强调数据库中不会保存不⼀致状态
隔离性强调数据库中事务之间相互不可⻅
持久性强调数据库能永久保存数据,⼀旦提交就不可撤销
事物使用:
数据库
存储引擎
是数据库底层软件组织,不同的 存储引擎 提供不同的存储机制、索引技巧、锁定⽔平 等功能,使⽤不同的存储引擎,还可以 获得特定的功能。
查看表引擎:show engines;
表的引擎类型必须是innodb类型才可以使⽤事务
,这是ubuntu 中 mysql表的默认引擎
开启事物: begin;(start transaction;
操作数据库:insert update delete
提交 事物:commit;
(提交后就不可以rollback)
回滚事物:rollback;
(没有提交可以回滚)
总结:
范式就是设计数据库的通⽤规范。
1NF强调字段是最⼩单元,不可再分
2NF强调在1NF基础上必须要有主键和⾮主键字段必须完全依赖于主键,也就是说 不能部分 依赖
3NF强调在2NF基础上 ⾮主键字段必须直接依赖于主键,也就是说不能传递依赖(间接依赖)。
E-R图即实体-联系图(Entity Relationship Diagram),是指提供了表示实体型、属性和联系的⽅法,⽤ 来描述现实世界的概念模型。
E-R图⽤ 实体、联系和属性这3个概念来描述现实问题。 有以下三种元素:
1 实体型(Entity):具有相同属性的实体具有相同的特征和性质,⽤实体名及其属性名集合来抽象 和刻画同类实体;在E-R图中⽤ 矩形 表示,矩形框内写明实体名;⽐如 电商购物系统中⽤户、购物 ⻋、订单等都是实体。
2 属性(Attribute):实体所具有的某⼀特性,⼀个实体可由若⼲个属性来刻画。在E-R图中⽤ 椭圆 形表示,并⽤⽆向边将其与相应的实体连接起来;⽐如⽤户的ID、⽤户名、密码、昵称、身份证 号码 都是属性。
3 联系(Relationship): 实体彼此之间相互连接的⽅式称为联系,也称为关系。联系可分为以下 3 种类型:⼀对⼀、⼀对多、多对多
========================简单的连接数据库并查询表的数据==========================
# 导入模块
from pymysql import connect
# 建立连接对象 pymysql.connect
conn = connect(host='localhost', user='root', password='12345678', database='python')
# 创建游标对象
cur = conn.cursor()
# 使用游标对象执行SQL语句
# execute 返回值是影响的行数,如果是查询语句,此处返回值为总记录数
result = cur.execute("select * from classes")
print("查询到:%s条数据" % result)
# 获取执行的结果(一行)并打印
# result_one = cur.fetchone()# 元组
# print(result_one)
# 所有数据
result_all = cur.fetchall()
print(result_all)
for i in result_all:
print(i)
# 关闭游标对象
cur.close()
# 关闭连接对象
conn.close()
==========================简单的连接数据库并增删改查表的数据=============================
from pymysql import connect
conn = connect(host='localhost', user='root', password='12345678', database='python')
cur = conn.cursor()
# sql = "insert into classes values(null,'python27',41)" #增
# sql = "delete from classes where id=7" #删
sql = "update classes set num=24 where id=8" # 改
result = cur.execute(sql)
conn.commit() # 提交刚刚执行的SQL,将修改提交到数据库,保存修改 ************************************
print("影响的行数:", result)
cur.fetchall()
cur.close()
conn.close()
SQL注⼊ 产⽣原因:
后台将⽤户提交的带有恶意的数据和SQL进⾏字符串⽅式的拼接,从 ⽽影响了SQL语句的语义,最终产⽣数据泄露的现象。
防注入的思路(sql语句的参数化):
from pymysql import connect
conn = connect(host='localhost', user='root', password='12345678', database='python')
cur = conn.cursor()
input_name = input("请输入要查询的班级:")
# 被注入过程的分析:
# input_name = ' or 1 or '
# "select * from classes where name= '%s' " % input_name 将%s替换为输入内容
# "select * from classes where name= '' or 1 or '' " % input_name 永远为真
# 防止注入(传参数)
# 1.构建参数列表params 2.把列表传递给 execute(sql,params)
params = [input_name]
# sql = "select * from classes where name= '%s' " % input_name
# 修改sql语句
sql = "select * from classes where name= %s "
# 修改execute()
result = cur.execute(sql,params)
print("影响的行数:", result)
result_all = cur.fetchall()
print(result_all)
cur.close()
conn.close()
索引 是⼀种特殊的⽂件(InnoDB数据表上的索引是表空间的⼀个组成部分),它们包含着对数据表⾥所 有记录的位置信息。
查看表中已有的索引: show index from 表名;
创建索引: create index 索引名称 on 表名(字段名称(长度)) ;
删除索引:drop index 索引名称 on 表名;
从上面这个图看出创建索引后,查找快了许多(索引可以明显提高某些字段的查询效率,)!!!!!
注意:
索引虽好但不要贪杯
所有⽤户及权限信息存储在mysql数据库的user表中
以管理员身份运行cmd后,启动mysql服务器,登录root(超级管理员)
使用 show databases;
可以看到系统默认有四个数据库(information_schema/ mysql/performance_schema/ sys)
使用 use mysql;
进入mysql数据库
使用 show tables;
查看mysql数据库中的所有表
使用 desc user;
查看mysql数据库中的user表,可以看到Host、 User、authentication_string 允许访问的主机、用户名、密码(用md5加密)字段
如果在⽣产环境下操作数据库时也是全部直接使⽤root账户连接,这就和悬崖边跳舞差不多。所以
创建特定的账户,授予这个账户特定的操作权限, 然后连接进⾏操作 ⽐如常规的crud 才是正道。
create user '用户名'@'主机' identified by ‘密码’;
grant 权限 on 数据库.表名 to '用户名' @'主机名';
1. create user 'wenmei'@'localhost' identified by '123456';(只能在localhost访问)
create user 'wenmei'@'%' identified by '123456';(任意电脑访问)
2. grant select on python.* to 'wenmei'@'localhost';(只用select权限,python数据库的所有表)
grant all privileges on python.* to 'wenmei'@'localhost';(所有权限)
3. (刷新一下权限)flush privileges;
4. 查看用户有哪些权限: show grants for wenmei@localhost;
grant 权限名称 on 数据库 to 账户@主机 with grant option;
如: grant upadate,insert on python to wenmei@localhost with grant option;
使⽤root登录,修改mysql数据库的user表 wenmei的密码
alter user 'wenmei'@'localhost' identified by '123' ;
flush privileges; 修改完成需要刷新权限
在不知道密码的情况下(忘记密码),修改密码:(密码置空+修改密码)
第一步,停止MySQL服务
输入命令net stop mysql( # linux service mysqld stop ),停止mysql服务,再用 netstat -an|findstr "3306" 查看mysql服务是否开启
第二步:在mysql8系统下,用mysqld --console --skip-grant-tables --shared-memory可以无密码启动服务
第三步: 服务启动后,以空密码登入系统 mysql.exe -u root
,然后执行sql命令将root用户密码设置为空
use mysql;
update user set authentication_string='' where user='root';
net start mysql
mysql -uroot -p 直接回车就可以登录成功
alter user 'root'@'%' identified by 'mysql';
flush privileges;
注意:
编辑MySQL 服务器配置文件:(linux :/etc/mysql/mysql.conf.d/mysqld.cnf)windows下的my.ini
加入一行 skip-grant-tables #跳过数据库权限验证
或者运行这个命令mysqld –skip-grant-tables
这些方法在MySQL8.0版本不适用,遇到了如下报错:
mysql: [ERROR] unknown option ‘–skip-grant-tables’.
当然也可以参考网上 利用–init-file参数解决
使用root登录,use mysql;使用mysql数据库,然后查看有哪些用户`select host,user from user;`
drop user '用户名'@'主机';
1.数据库系统通常采用三级模式,模式(逻辑模式,只有一个)、内模式(存储模式,一个)、外模式(子模式/用户模式,多个)
2.数据库的二级映像:
外模式/模式映像 保证了逻辑独立性
模式/内模式 保证了物理独立性