一、 数据库简介
1.什么是数据库?
1)数据库是“按照数据结构来组织、存储和管理数据的仓库”:
- 是一个长期存储在计算机内的、有组织的、有共享的、统一管理的数据集合。
- 数据库是以一定方式储存在一起、能与多个用户共享、具有尽可能小的冗余度、与应用程序彼此独立的数据集合,可视为电子化的文件柜——存储电子文件的处所,用户可以对文件中的数据进行新增、查询、更新、删除等操作。
- 数据库是存放数据的仓库。它的存储空间很大,可以存放百万条、千万条、上亿条数据。
- 但是数据库并不是随意地将数据进行存放,是有一定的规则的,否则查询的效率会很低。
- 当今世界是一个充满着数据的互联网世界,充斥着大量的数据。即这个互联网世界就是数据世界。
- 数据的来源有很多,比如出行记录、消费记录、浏览的网页、发送的消息等等。
- 除了文本类型的数据,图像、音乐、声音都是数据。
2)数据库是一个按数据结构来存储和管理数据的计算机软件系统。数据库的概念实际包括两层意思:
- 数据库是一个实体,它是能够合理保管数据的“仓库”,用户在该“仓库”中存放要管理的事务数据,“数据”和“库”两个概念结合成为数据库。
- 数据库是数据管理的新方法和技术,它能更合适的组织数据、更方便的维护数据、更严密的控制数据和更有效的利用数据。
2.为什么需要数据库?
- 人类在进化的过程中,创造了数字、文字、符号等来进行数据的记录,但是承受着认知能力和创造能力的提 升,数据量越来越大,对于数据的记录和准确查找,成为了一个重大难题。
- 数据库系统解决的问题:持久化存储,优化读写,保证数据的有效性。
3.常见数据库有哪些?
1)计算机诞生后,数据开始在计算机中存储并计算,并设计出了数据库系统。
2)数据库分类:
关系型数据库:指采用了关系模型来组织数据的数据库。关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织。主流的关系型数据库有:Oracle、Microsoft SQL Server、MySQL、PostgreSQL,SQLite、MariaDB(MySQL的一个分支)Microsoft Access、SAP。
非关系型数据库:指非关系型的,分布式的,以键值对存储且结构不固定,可以减少一些时间和空间的开销。非关系型数据库都是针对某些特定的应用需求,主要分为以下几类:
1). 面向海量数据访问的面向文档数据库:MongoDB、Amazon DynamoDB、Couchbase等。
2). 面向高性能并发读写的key-value数据库: Redis、 Memcached等。
3). 面向搜索数据内容的搜索引擎:Elasticsearch,Splunk,Solr,MarkLogic和Sphinx等。
4). 面向可扩展性的分布式数据库:Cassandra,HBase等。
注意:Mysql 是一个开源免费数据库,自从被甲骨文公司收购之后,和Oracle一样通属于甲骨文公司,但Oracle是一个收费的数据库,一般在企业中除了银行一类公司,并不会选用Oracle的,所以Mysql创始人担心Mysql的发展前景,又开发了MariaDB数据库,也是开源数据库并且和Mysql的使用方式以及基本操作几乎相同,所以我们在使用中会优先使用MariaDB数据库。
二、关系型数据库
关系型数据库的关键有两个: E-R图和三大范式:
1、E-R模型
1)基本概念:
当前物理的数据库都是按照E-R模型进行设计的,
- E表示entry,实体
- R表示relationship,关系
- 一个实体转换为数据库中的一个表。
- 关系描述两个实体之间的对应规则,包括: 一对一 ,一对多, 多对多。
2)范式理解:
经过研究和对使用中问题的总结,对于设计数据库提出了一些规范,这些规范被称为范式:
- 第一范式(1NF):列不可拆分 , 即无重复的域。
- 第二范式(2NF):唯一标识 ,即拥有实体的唯一标识(eg: 身份证、id号等)。
- 第三范式(3NF):引用主键 ,即每列数据都与主键直接相关。
说明:关系型数据库有六种范式。一般说来,数据库只需满足第三范式(3NF)就行了。
3)范式判断理解案例:
1》范式判断: 是否符合第一范式?
第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项。
符合第一范式的特点就有:有主关键字、主键不能为空、主键不能重复,字段不可以再分。
答案: 不符合。 键重复,而且【联系方式】字段可以再分。
变更为正确的是:
2》范式判断: 是否符合第一范式?Why?
答:1NF的定义为:符合1NF的关系中的每个属性都不可再分。因此不符合1NF的要求。
RDBMS中表现表中的数据,就得设计为下表的形式:
3》范式判断: 是否符合第二范式?Why?
第二范式是指每个表必须有且仅有一个数据元素为主关键字(Primary key),其他数据元素与主关键字一一对应。这种关系为函数依赖。
符合第二范式的特点就有:满足第一范式的前提下,消除部分函数依赖。
答: 不符合。 班级地址部分依赖于关键字班级编号, 所以要变为两个表,如下:
4》范式判断: 是否符合第二范式?Why?
数据冗余过大,插入异常,删除异常,修改异常的问题,如下表所示:
1). 每一名学生的学号、姓名、系名、系主任这些数据重复多次。每个系与对应的系主任的数据也重复多次(数据冗余过大)
2). 假如学校新建了一个系,但是暂时还没有招收任何学生,那么是无法将系名与系主任的数据单独地添加到数据表中去的(插入异常)
3). 假如将某个系中所有学生相关的记录都删除,那么所有系与系主任的数据也就随之消失了。(删除异常)
4). 假如李小明转系到法律系,那么为了保证数据库中数据的一致性,需要修改三条记录中系与系主任的数据。(修改异常)
所以上表修改成如下就符合第二范式:
5》范式判断: 是否符合第三范式?Why?
符合第三范式的特点就有:不存在非主属性对码的传递性依赖以及部分性依赖 。
答: 不符合。 完全满足了第二范式,但是奖金等级和奖学金存在传递依赖,更改为:
4.范式
1)基本概念:
- 三大范式只是一般设计数据库的基本理念,可以建立冗余较小、结构合理的数据库。
- 如果有特殊情况,当然要特殊对待,数据库设计最重要的是看需求跟性能,需求>性能>表结构。
- 所以不能一味的去追求范式建立数据库。
5.个人博客数据库设计
- 新浪博客、搜狐、网易博客开通账号直接在上面写博客。
- 不过,如今随着网络的发展,越来越多的高手会开源分享自己撰写的程序。
- 如今我们需要做网站基本上都可以找到免费的程序。
- 比如如果我们需要做个人博客网站的时候,有很多的开源博客程序可以选择,比如WORDPRESS、ZBLOG等等。
注:个人博客系统主要完成以下几方面的功能,我们要如何设计数据库表呢?
- 用户管理:用户的注册和登录,发表博文和评论。
- 博文管理:用户可以在网站中发表和设置博文。
- 评论管理:用户可以评论博文和回复其他用户的评论。
- 分类管理:添加和删除分类,给文章设置分类。
- 管理:添加和删除标签,给文章设置标签。
二、MySQL简介与安装
- MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。
- MySQL 是最流行的关系型数据库管理系统之一。
MariaDB,据说是MySQL被甲骨文公司收购后,他的创始人担心MySQL就此没落,又创立出来的一个分支,maria是他的第四个女儿的名字,MariaDB使用起来与MySQL没差。
cs架构:客户端–服务器端
bs架构:浏览器端–服务器端
MySQL属于cs架构
服务端为mtsql sever,分为三层:
(1)连接层: 用于客户端限制
(2)SQL层:一些SQL语句的定义
(3)存储引擎层:以什么方式存储的。
数据库存储引擎是数据库底层软件组织,进行创建、查询、更新和删除数据。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能。
1、MySQL常用存储引擎分析
- 数据库存储引擎是数据库底层软件组织,进行创建、查询、更新和删除数据。
- 不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能,MySQL的核心就是存储引擎。
- MySQL查询存储引擎SQL语句:SHOW ENGINES。
2.安装步骤:
1)查找并yum安装:(必须用root用户)
yum search mariadb
yum install mariadb-server.x86_64 -y
第一步:切换到root用户:
第二步:搜索并安装mariadb(前提是yum源搭建成功才能安装成功)
可见mariadb安装成功了!
3.数据库服务管理:
systemctl stop firewalld #关闭防火墙
systemctl status firewalld #查看防火墙状态
systemctl start mariadb #开启mariabd服务
systemctl status mariadb #查看mariadb状态
systemctl stop mariadb #关闭mariadb服务
systemctl start mariadb
systemctl enable mariadb #设置mariadb服务开机自启动
此时mariadb服务是关闭的,无法使用,再次开启。
可见目前mariadb状态是开启着的,并且防火墙也是关闭着的。
4.安全性密码设置
我们作实验的过程中,数据库没有密码是没有关系的,但是,如果在实际工作当中,如果不进行安全性密码设置,那么我们的数据库会很不安全,因此需要进行安全性设置。
mysql_secure_installation
第一步:输入进入安全性设置,
到此处,mysql的密码就设置好了!密码为(westos).
可见,我的mysql数据库设置并登陆成功。
1.允许远程连接
1). 关闭mysql服务器的防火墙
systemctl stop firewalld
systemctl disable firewalld
2). 用户授权: 允许root用户通过westos密码 在任意主机(%)远程登陆并操作数据库;
grant all privileges on *.* to root @'%' identified by 'westos';
#这里面的%可以换成客户端的ip,westos只是数据库的,密码,自己设置的是什么就用什么。
客户端: 172.25.254.18
服务端:172.25.254.197
需求:客户端18可以远程连接服务端197数据库
3)服务端操作:
1》服务端关闭mysql服务器的防火墙:systemctl stop firewalld > systemctl disable firewalld(之前的实验当中已经完成了)
2》登陆自己的数据库:mysql -uroot -p
3》查看mysql中数据库表user的三列(查看此时都有谁可以连接服务端数据库):select Host,User,Passwod from mysql.user
4》允许客户端以root身份密码为westos授权登陆,%表示任意 ip ; * .* 表示所有数据库中的所有数据库表: grant all on *.* to root@'%' identified by 'westos';
3)客户端测试:
1》mysql -h 172.25.254.18 -uroot -pwestos #以root身份密码为westos登陆服务端18的mysql数据库
2》删除远程登陆指定的用户授权:drop user root@'%'; %:任意用户 %换成指定ip表示删除指定用户的登陆授权。
可见通过drop之后,之前连接过服务端的ip都没有了,如果需要再次登陆,需要服务端重新授权才可以。
注意:此实验成功的前提是客户端和服务端都成功安装了mariadb并且是开启状态。
2、找回密码
如果你的mysql密码忘记了,也不要担心,可以通过以下操作找回密码:
#1)关闭mariadb服务
systemctl stop mariadb
#2)跳过授权表
mysqld_safe --skip-grant-table &
#3)修改root密码
mysql
> update mysql.user set Password=password('新密码') where User='root';
#4)关闭跳过授权表的过程,启动mariadb服务,使用新密码即可
ps aux | grep mysql
kill -9 pid
mysql -uroot -p
三、数据库操作
注意,SQL语句要在每句末尾加分号
1.数据库操作:
1)创建数据库
create database 数据库名 default charset=‘utf8’;#创建数据库可存储中文
2)查看数据库
show databases;
可见Blog创建成功了。
3)切换数据库
use 数据库名;
4)删除数据库(此处暂时不作演示)
drop database 数据库名;
5)查看当前所使用的数据库
select database();
可见目前使用的数据库是新创建的Blog.
数据库主要操作总结如下图:
2.数据库表操作
1)查看当前数据库中的所有表
show tables ;
创建表:
一个数据库就是一个完整的业务单元,可以包含多张表,数据被存储在表中,在表中为了更加准确的存储数据,保证数据的正确有效,可以在创建表的时候,为 表添加一些强制性的验证, 包括数据字段的类型、约束。
字段类型:
在mysql中包含的数据类型很多,这里主要列出来常用的几种:
• 数字:int,decimal, float
• 字符串:varchar,text
• 日期:datetime
• 布尔:bool
约束:
• 主键 primary key
• 非空 not null
• 惟一 unique
• 默认 default
• 外键 foreign key
• 自动增长 auto_increment
2)创建表:
create table 表名(列及类型);
例如:
create table userinfo(
-> username varchar(20) not null unique,
-> passwd varchar(20) not null);
创建表为两列:username、passwd username的类型为字符串可变长字节是20 不可为空、唯一。
3)为原先表userinfo添加一列sex
alter table userinfo add sex varchar(20);
可见添加成功。
4)将原先表中 sex一列改为gender
alter table userinfo change sex gender varchar(20);
修改成功。
5)删除userinfo中的gender列
alter table userinfo drop gender;
6)将表名称userinfo修改为users
rename table userinfo to users;
7)查看当前数据库的所有表
show tables;
8)查看创建当前表的sql语句
show create table 表名;
9)删除表
drop table 表名;
10)查看表结构
desc 表名;
表的主要操作如下图:
3.数据操作
1)创建表结构:
create table users(id int primary key auto_increment,username varchar(20)not null unique,passwd varchar(20) not null)
2)查看uers的数据,此时为空
select * from users;
3)向表中增加数据信息:
insert into users values('1','user1','666'); #全列插入表信息
insert into users(username) values('user2'),('user3');#同时插入2条数据。针对username这一列插入内容为user2,其余列自动插入默认值,
4)向表中更改数据信息:
update users set passwd='235' where username='user2'; #对表users将user2的passwd改为235 where后接指定条件
select * from users where username='user1' ;#指定查看表users内容为uesr1的数据信息
5)向表中删除数据信息:
delete from users where username='user1'; #删除表users中user1的信息
6)数据备份与恢复
mysqldump -uroot -pwestos 要备份的数据库名 > 新的备份文件.sql #备份
mysql -uroot -pwestos 本地存在的数据库名 < 备份文件.sql # 恢复:此处数据库名为要恢复的电脑中的数据库,备份文件.sql前面要加绝对路径。
概括起来如下两个表所示:
四、查询操作
1.查询的基本语法
select * from 表名;
- from关键字后面写表名,表示数据来源于是这张表
- select后面写表中的列名,如果是*表示在结果中显示表中所有列
- 在select后面的列名部分,可以使用as为列起别名,这个别名出现在结果集中
- 如果要查询多个列,之间使用逗号分隔
2.消除重复行
在select后面列前使用distinct可以消除重复的行
select distinct gender from students;
#查询students中不重复的sex(消除重复)
select distinct ssex from students;
3.查询的筛选条件
1)使用where子句对表中的数据筛选,结果为true的行会出现在结果集中
select * from 表名 where 条件;
2)优先级
•小括号,not,比较运算符,逻辑运算符
•and比or先运算,如果同时出现并希望先算or,需要结合()使用
# 查询scores表中成绩在60--80之间的记录 (筛选条件)
select * from scores where degree between 60 and 80;
# 查询scores表中成绩为85,86,87的记录
select * from scores where degree in (85,86,87);
3)分组
查询的分组
• 按照字段分组,表示此字段相同的数据会被放到一个组中
• 分组后,只能查询出相同的数据列,对于有差异的数据列无法出现在结果集中
• 可以对分组后的数据进行统计,做聚合运算,为了快速得到统计数据,提供了5个聚合函数:
select 列1,列2,聚合... from 表名 group by 列1,列2,列3...
#查询班级为9503的学生总人数
select count(*) as studentcount from students where class='9503';
#查询编号为3-105的学生成绩平均数
select avg(degree) as degreeavg from scores where cno='3-105';
4)分组后的数据筛选
group by xxx having xxx
having后面的条件运算符与where的相同
对比where与having
• where是对from后面指定的表进行数据筛选,属于对原始数据的筛选
• having是对group by的结果进行筛选
筛选条件先计算再判断使用group by先分组,对原始数据直接判断使用where,where是对from后面指定的表进行数据筛选,属于对原始数据的筛选。
# 查询socres表中drgree大于70小于90的sno列
select sno from scores where degree >70 and degree <90 ;
# 查询scores表中至少有5名学生选修的并以3开头的课程和对应的平均分数,
#分析:
# 课程和对应的平均分数都有一个共有条件:以3开头
# 至少有5名学生选修:count(cno)>=5 课程数大于等于5
# 以3开头的课程:cno like '3%' (不用计算使用where)
# 课程的平均分数:avg(degree)
select cno,avg(degree) from scores where cno like '3%' group by cno having count(cno)>=5;
# 查询scores中选学1门以上的课、分数为非最高分成绩的同学
#分析:
# 选学1门以上课:count(cno) >1
# 分数为非最高分成绩:degree != max(degree)
# 分组 按照学生分组 学生的条件为:选学1门以上课、分数为非最高分成绩
select * from scores group by sno having count(cno)> 1 and degree != max(degree);
4.排序
1)为了方便查看数据,可以对数据进行排序:
• 将行数据按照列1进行排序,如果某些行列1的值相同时,则按照列2排序,以此类推
• 默认按照列值从小到大排列
• asc从小到大排列,即升序, desc从大到小排序,即降序
order by xxx/xxx desc
#查询students表中以class为降序的内容
select * from students order by class desc;
#查询students表中以class为生序的内容
select * from students order by class ;
#查询scores表中cno为生序degree为降序的内容(此时cno相同时degree为降序显示)
select * from scores order by cno,degree desc;
2)获取部分行
当数据量过大时,在一页中查看数据是一件非常麻烦的事情:
• 从start开始,获取count条数据
• start索引从0开始
limit start count
#查询成绩最高的前5名学生信息
select * from scores order by degree limit 5;
select * from scores order by degree desc limit 2,3;从第二个索引开始获取3条数据
#嵌套查找
#查询scores表中最高分的学生学号和课程号
select sno,cno from scores where degree=(select max(degree) from scores);
3)空判断与模糊查询
#空判断:
insert into courses(cno,cname) values(3-666,'概率论'); #只对前两列输入值对最后一列不输入值
select * from courses where tno='';#查询最后一列为空时的结果
#模糊查询:_单个字符两个下划线表示两个字符
select * from courses where cname like '%数学%';#查找包含cname包含数学的内容
select * from courses where cname like '__数学
4)多表查询
# 两个表的拼接:
# 查询所有学生的sname、cno和degree列
# 分析:sname、cno在student表中,degree在scores表中,两个表中有相同的列为sno,当两个表中sno相同时拼接其余值。on后跟条件
# 等值拼接:
select sname ,cno ,degree from students inner join scores on students.sno=scores.sno;
# 三个表的拼接:
# 查询所有学生的sname、cname和degree列
# 分析:sname在student表中,cname在courses表中,degree在scores表中,
# student表与scores表中有相同的列为sno,scores表与courses表有相同的列为cno,先拼接两个表在拼接第三个表。
select sname ,cname ,degree from students inner join scores on students.sno=scores.sno
inner join courses on scores.cno=courses.cno;
总结:注意: 实际使用中,只是语句中某些部分的组合,而不是全部
执行顺序为:
1. from 表名
2. where ....
3. group by ..
4. select distinct *
5. having ...
6. order by ...
7. limit star,count
5.练习
#练习题:
# 查询95033班所选课程的平均分
# 分析:degree在scores表中、cname在courses表中,相同的列为cno
select avg(degree) from scores inner join courses on scores.cno=courses.cno;
# 查询95033班和95031班全体学生的记录
select *from students where class=95031 or class=95033;
# 查询student表中不姓王的同学记录
select *from students where sname not like '王%';
# 查询所有任课教师的Tname和Depart
select tname,depart from teachers;
# 查询所有未讲课的教师的Tname和Depart
select tname,depart from teachers where prof != '讲师';
# 查询students表中95031班或性别为女的同学记录
select *from students where class=95031 or ssex='女';
五、 pymysql数据库编程
1.PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使用MySQLdb。
2.安装:
pip install -i https://pypi.douban.com/simple pymysql
#或者:
pip install pymysql
可见安装成功!
pycharm中:pymysql数据库编程两种步骤:
步骤一:
import pymysql
#创建数据库连接,autocommit自动提交修改到数据库(设置为True才可以在数据库中看到修改的内容)
conn=pymysql.connect(host='localhost',user='root',password='westos',db='Blog',port=3306,autocommit=True,charset='utf8')
#创建游标(用于执行sql语句)
cur=conn.cursor()
#执行sql语句
insert_sql='insert into users(username) values ("user7");'
cur.execute(insert_sql)
print('ok')
#关闭游标
cur.close()
#关闭连接
conn.close()
步骤二:
#使用with语句自动关闭 pymysql.connect为上下文管理器可以使用with语句
"""
connect的部分源码为:
Context manager that returns a Cursor(返回一个游标的上下文管理器)
def __enter__(self):
warnings.warn(
"Context manager API of Connection object is deprecated; Use conn.begin()",
DeprecationWarning)
return self.cursor()
On successful exit, commit(提交). On exception, rollback(回滚到一开始的操作)
def __exit__(self, exc, value, traceback):
if exc:
self.rollback()
else:
self.commit()
"""
#数据库插入修改操作
import pymysql
users=['westos'+str(i) for i in range(100)]
with pymysql.connect(host='localhost',user='root',password='westos',
db='Blog',port=3306,autocommit=True,charset='utf8') as cur: #返回一个游标存为cur
insert_sql='insert into users(username) values ("user9");'
cur.execute(insert_sql) #执行一条sql语句
insert_sql='insert into users(username) values ("%s");' #%s占位符
cur.executemany(insert_sql,users) #执行多条sql语句,values ("%s") %users[0]逐渐递增
print('ok')
#数据库查询与获取操作
import pymysql
with pymysql.connect(host='localhost',user='root',password='westos',
db='Blog',port=3306,autocommit=True,charset='utf8') as cur: #返回一个游标存为cur
query_sql='select * from users where username like "user%";'#查找username以user开头的内容
result=cur.execute(query_sql) #cur.execute返回找到的数目
print('符合条件数为: ',result)
获取符合条件的内容
print(cur.fetchone())#获取一条
print(cur.fetchmany(2))#获取2条 指针移动到获取完第一条的下一条来获取
print(cur.fetchall())#获取所有
#美观查看内容
from prettytable import PrettyTable
pt=PrettyTable(field_names=['编号','用户','密码'])
for i in cur.fetchall():
pt.add_row(i)
print(pt)
#执行结果:
符合条件数为: 5
+------+-------+--------+
| 编号 | 用户 | 密码 |
+------+-------+--------+
| 2 | user2 | 235 |
| 3 | user3 | 000000 |
| 4 | user7 | 000000 |
| 5 | user8 | 000000 |
| 6 | user9 | 000000 |
+------+-------+--------+
六、sqlite数据库
1.什么是sqlite数据库?
- SQLite是内嵌在Python中的轻量级、基于磁盘文件袋额数据库管理系统(就是一个文件),
- 不需要安装和配置服务,支持使用SQL语句来访问数据库。该数据库使用C语言开发,支持大多数SQL91标准,
- 支持原子的、一致的、独立的和持久的事务,不支持外键限制;通过数据库级的独占性和共享性锁定来实现独立事务,
- 当多个线程同时访问同一个数据库并试图写入数据时,每一时刻只有一个线程可以写入数据。
2.sqlite数据库的特性:
SQLite支持最大140TB大小的单个数据库,每个数据库完全存储在单个磁盘文件中,以B+树数据结构的形式存储,一个数据库就是一个文件,通过直接复制数据库文件就可以实现数据库的备份。如果需要使用可视化管理工具,可以下载并使用SQLiteManager、SQLite Database Browser 或其他类似工具。
#sqlite数据库
import sqlite3
conn=sqlite3.connect(database='users.sqlite')
cur=conn.cursor()
#if not exists如果数据库表不存在时创建表,否则不做任何操作
create_sql='create table if not exists users (id int primary key ,name varchar (10),passwd varchar (10) default "123" );' #id为主键自动递增
cur.execute(create_sql)
insert_sql='insert into users(name) values ("user2");'#对name这一列插入user1
count = cur.execute(insert_sql)
conn.commit() #数据操作(增删改)一定要提交。连接提交修改的语句
select_sql='select * from users' #查询users表的内容
cur.execute(select_sql)
print(cur.fetchall()) #获取表的内容
cur.close()
conn.close()
总结:除了基本的数据库操作命令以外,还要掌握导入数据库的方法,后期会对相关内容再进行补充。