人类在进化的过程中,创造了数字、文字、符号等来进行数据的记录,往石头和龟壳上面画上,到时候一数,但是承受着认知能力和创造能力的提升,数据量越来越大,对于数据的记录和准确查找,成为了一个重大难题
数据库的前世今生
数据库是什么?
首先我们先来聊聊数据库,首先数据库是什么意思,其实就是数据的仓库,而数据才是最关键的,现在大家所说的大数据大数据,其实说白了数据才是核心,通过各种算法要分析数据。
为什么我们需要数据库?
其实在一些传统的大企业来说,有的在使用纸质文件(那就要注意防火、防潮),有的在使用excel来存储数据,这个是真实存在的,上一家单位就是这样,公司人员excel的各种公式很66 的,但是也面临着改革
公司里面都开始提倡无纸化办公,让打印出来纸质的资料越来越少,连公司前台的签到都变成了二维码,而excel里面的大量的数据累积,让我们查找和维护变的异常困难,存储这些文件的服务器变的重要多了,万一中了个病毒倒了下去,这些数据再也没有办法恢复过来
数据库解决的问题
持久化存储,优化读写(并不是简单的IO读写,每个数据库这个才是核心,算法不同),保证数据的有效性(比如有效的身份证号,以前手工录入很容易出现重复的)
常用的数据库种类都有什么
- 关系型数据库(Oracle/MySQL/SQL SERVER/ACCESS..)
- 非关系型数据库(MongoDB/Redis/Memcached..)
学习前的名词解释
MySQL的介绍
MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle公司(被Oracle收购)MySQL目前用的比较多,毕竟一个标签就是免费嘛,一些创业公司首选了http://www.mysql.com/ mysql官网
https://db-engines.com/en/ran... 数据库排名网站
MySQL是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性
MySQL的特点:
- Mysql是开源的,所以你不需要支付额外的费用
- Mysql支持大型的数据库。可以处理拥有上千万条记录的大型数据库
- MySQL使用标准的SQL数据语言形式
- Mysql可以允许于多个系统上,并且支持多种语言。这些编程语言包括C、C++、Python、Java、Perl、PHP、Eiffel、Ruby和Tcl等。
- Mysql对PHP有很好的支持,PHP是目前最流行的Web开发语言。
- MySQL支持大型数据库,支持5000万条记录的数据仓库,32位系统表文件最大可支持4GB,64位系统支持最大的表文件为8TB。
- Mysql是可以定制的,采用了GPL协议,你可以修改源码来开发自己的Mysql系统。
上次去听京东的技术峰会,京东的数据库就是基于Mysql进行了定制化开发
MySQL的安装图解
数据库设计
E-R模型
ER模型最早由Peter Chen(陈品山)于1976年提出,当前物理的数据库都是按照E-R模型进行设计的(E表示entry,实体,R表示relationship,关系)一个实体转换为数据库中的一个表,关系描述两个实体之间的对应规则,包括(一对一,一对多,多对多)
通俗点理解下关系:
一对一:一个部门有一个经理,而每个经理只在一个部门任职,则部门与经理的联系是一对一的
一对多:一个员工可以同时是多个部门的经理,而一个部门只能有一个经理,则这种规定下“员工”与“部门”之间的“管理”联系就是1:n的联系了
多对多:一个员工可以同时在多个部门工作,而一个部门有多个员工在其中工作,则“员工”与“部门”的“工作”联系为m:n联系
数据库设计阶段,我们会通过工具(Visio/PowerDesigner..)绘制E-R图,E-R图也称实体-联系图(Entity Relationship Diagram),提供了表示实体类型、属性和联系的方法,用来描述现实世界的概念模型
数据库设计规范:三范式
第一范式(1NF):列不可拆分,比如姓名已经不可以再拆,但是这个要根据具体的业务逻辑走,你可以再拆,姓一个字段,名一个字段
第二范式(2NF):唯一标识,可以通过一个属性唯一的找到这个对象,如果没有这个标识很容易造成数据重复,冗余 (注意:数据库设置的时候范式都要满足)
第三范式(3NF):引用主键,这个是基于第二范式来说的,一个表想引用另外一个表的数据,那么需要主键来引用,需要唯一标识
上面这些规范不仅仅是作用mysql数据库,只要是关系型数据库都应该遵守上面的规范
mysql中常用的字段类型
数字:int (整数) decimal(5,2) 保留2位小数,5是整数部分加小数部分的总长度
字符串:char,varchar,text(大文本)
char与varchar后面接的数据大小为存储的字符数
char是固定长度,如果字符数没有达到定义位数会在后面自动补空格 例:char(5) 'abc '
varchar是变长长度,例:varchar(5) 'abc' 不会帮你补空格
日期:datetime
布尔:bit
约束
- 主键primary key
- 非空not null
- 唯一 unique
- 默认default
- 外键foreign key
SQL语言
先来说说什么是SQL?
SQL(SQL 是一种 ANSI 的标准计算机语言 【ANSI,美国国家标准化组织】) 是用于访问和处理数据库的标准的计算机语言,使我们有能力访问数据库(Oracle, Sybase, SQL Server, DB2, Access 等等)
SQL能做什么? 帮你操作数据库,比如执行查询、删除、修改、添加、创建表、存储过程、视图等等等你想要对数据库做的操作都可以
那是不是学会SQL 就可以对上面那群数据库操作了,只能说大部分是的,但是个别情况会有点区别,因为SQL语言的版本问题。
查询操作
查询的基本语法:
select * from 表名;
解读下上面这条语句:
- from关键字后面写表名,表示数据来源于是这张表
- select后面写表中的列名,如果是*表示在结果中显示表中所有列
- 在select后面的列名部分,可以使用as为列起别名,这个别名出现在结果集中
- 如果要查询多个列,之间使用逗号分隔
消除重复行
在select后面列前使用distinct可以消除重复的行
select distinct gender from students;
根据条件查询
语法如下:
select * from 表名 where 条件;
使用where子句对表中的数据筛选,结果为true的行会出现在结果集中
比较运算符包括 = > < >= <= !=或<>
比较运算符的栗子:
/*查询编号大于3的学生*/
select * from students where id>3;
/*查询编号不大于4的科目*/
select * from subjects where id<=4;
/*查询姓名不是“黄蓉”的学生*/
select * from students where sname!='黄蓉';
/*查询没被删除的学生*/
select * from students where isdelete=0;
逻辑运算符包括 and or not
逻辑运算符的栗子:
/*查询编号大于3的女同学*/
select * from students where id>3 and gender=0;
/*查询编号小于4或没被删除的学生*/
select * from students where id<4 or isdelete=0;
模糊查询
- like
- %表示任意多个任意字符
- _表示一个任意字符
/*查询姓黄的学生*/
select * from students where sname like '黄%';
/*查询姓黄并且名字是一个字的学生*/
select * from students where sname like '黄_';
/*查询姓黄或叫靖的学生*/
select * from students where sname like '黄%' or sname like '%靖%';
范围查询
- in表示在一个非连续的范围内
- between ... and ...表示在一个连续的范围内
/*查询编号是1或3或8的学生*/
select * from students where id in(1,3,8);
/*查询学生是3至8的学生*/
select * from students where id between 3 and 8;
/*查询学生是3至8的男生*/
select * from students where id between 3 and 8 and gender=1;
空判断
注意:null与''是不同的,判空is null 判非空is not null
/*查询没有填写地址的学生*/
select * from students where hometown is null;
/*查询填写了地址的学生*/
select * from students where hometown is not null;
/*查询填写了地址的女生*/
select * from students where hometown is not null and gender=0;
优先级
- 小括号,not,比较运算符,逻辑运算符
- and比or先运算,如果同时出现并希望先算or,需要结合()使用
聚合
为了快速得到统计数据,提供了5个聚合函数:
- count(*)表示计算总行数,括号中写星与列名,结果是相同的
- max(列)表示求此列的最大值
- min(列)表示求此列的最小值
- sum(列)表示求此列的和
- avg(列)表示求此列的平均值
栗子:
/*查询学生总数*/
select count(*) from students;
/*查询女生的编号最大值*/
select max(id) from students where gender=0;
/*查询未删除的学生最小编号*/
select min(id) from students where isdelete=0;
/*查询男生的编号之后*/
select sum(id) from students where gender=1;
/*查询未删除女生的编号平均值*/
select avg(id) from students where isdelete=0 and gender=0;
分组
按照字段分组,表示此字段相同的数据会被放到一个组中,分组后,只能查询出相同的数据列,对于有差异的数据列无法出现在结果集中,可以对分组后的数据进行统计,做聚合运算
语法:
select 列1,列2,聚合... from 表名 group by 列1,列2,列3...
栗子:
/*查询男女生总数*/
select gender as 性别,count(*)
from students
group by gender;
/*查询各城市人数*/
select hometown as 家乡,count(*)
from students
group by hometown;
分组后的数据筛选
语法:
select 列1,列2,聚合... from 表名
group by 列1,列2,列3...
having 列1,...聚合...
having后面的条件运算符与where的相同
/*查询男生总人数*/
方案一
select count(*)
from students
where gender=1;
-----------------------------------
方案二:
select gender as 性别,count(*)
from students
group by gender
having gender=1;
对比where与having
- where是对from后面指定的表进行数据筛选,属于对原始数据的筛选
- having是对group by的结果进行筛选
排序
为了方便查看数据,可以对数据进行排序,语法:
select * from 表名
order by 列1 asc|desc,列2 asc|desc,...
注意:
- 将行数据按照列1进行排序,如果某些行列1的值相同时,则按照列2排序,以此类推
- 默认按照列值从小到大排列
- asc从小到大排列,即升序
- desc从大到小排序,即降序
栗子:
/*查询未删除男生学生信息,按学号降序*/
select * from students
where gender=1 and isdelete=0
order by id desc;
/*查询未删除科目信息,按名称升序*/
select * from subject
where isdelete=0
order by stitle;
获取部分行
当数据量过大时,在一页中查看数据是一件非常麻烦的事情。
语法:
select * from 表名
limit start,count
从start开始,获取count条数据,start索引从0开始
示例:分页
已知:每页显示m条数据,当前显示第n页
求总页数:此段逻辑后面会在python中实现
查询总条数p1
使用p1除以m得到p2
如果整除则p2为总数页
如果不整除则p2+1为总页数
求第n页的数据
/*语法*/
select * from students
where isdelete=0
limit (n-1)*m,m
栗子
查询第1条到第10条的数据的sql是:select from table limit 0,10; ->对应我们的需求就是查询第一页的数据:select from table limit (1-1)*10,10;
查询第10条到第20条的数据的sql是:select from table limit 10,20; ->对应我们的需求就是查询第二页的数据:select from table limit (2-1)*10,10;
高级查询
关系
我们去设计数据库的时候会存在表与表之间的依赖关系,那么查询的时候就会设计到依赖关系的连接查询
连接查询
连接查询分类如下:
- 表A inner join 表B:表A与表B匹配的行会出现在结果中
- 表A left join 表B:表A与表B匹配的行会出现在结果中,外加表A中独有的数据,未对应的数据使用null填充
- 表A right join 表B:表A与表B匹配的行会出现在结果中,外加表B中独有的数据,未对应的数据使用null填充
注意:在查询或条件中推荐使用“表名.列名”的语法,如果多个表中列名不重复可以省略“表名.”部分,如果表的名称太长,可以在表名后面使用' as 简写名'或' 简写名',为表起个临时的简写名称
栗子:
/*查询学生的姓名、平均分*/
select students.sname,avg(scores.score)
from scores
inner join students on scores.stuid=students.id
group by students.sname;
子查询
子查询指的是查询的嵌套
select sname,
(select sco.score from scores sco inner join subjects sub on sco.subid=sub.id where sub.stitle='语文' and stuid=stu.id) as 语文,
(select sco.score from scores sco inner join subjects sub on sco.subid=sub.id where sub.stitle='数学' and stuid=stu.id) as 数学,
(select sco.score from scores sco inner join subjects sub on sco.subid=sub.id where sub.stitle='英语' and stuid=stu.id) as 英语
from students stu;
内置函数
字符串函数
- 查看字符的ascii码值ascii(str),str是空串时返回0 select ascii('a')
- 查看ascii码值对应的字符char(数字) select char(97);
- 拼接字符串concat(str1,str2...) select concat(12,34,'ab');
- 包含字符个数length(str) select length('abc');
- 截取字符串 left(str,len)返回字符串str的左端len个字符
- 截取字符串 right(str,len)返回字符串str的右端len个字符
- 截取字符串 substring(str,pos,len)返回字符串str的位置pos起len个字符 select substring('abc123',2,3);
- 去除空格 ltrim(str)返回删除了左空格的字符串str
- 去除空格 rtrim(str)返回删除了右空格的字符串str
- 去除空格 trim([方向 remstr from str)返回从某侧删除remstr后的字符串str,方向词包括both、leading、trailing,表示两侧、左、右 select trim(both 'x' FROM 'xxxbarxxx');
- 返回由n个空格字符组成的一个字符串space(n) select space(10);
- 替换字符串replace(str,from_str,to_str) select replace('abc123','123','def');
- 大小写转换,函数如下 lower(str) upper(str) select lower('aBcD');
数学函数
- 求绝对值abs(n) select abs(-32);
- 求m除以n的余数mod(m,n),同运算符% select mod(10,3);
- 地板floor(n),表示不大于n的最大整数 select floor(2.3);
- 天花板ceiling(n),表示不小于n的最大整数 select ceiling(2.3);
- 求四舍五入值round(n,d),n表示原数,d表示小数位置,默认为0 select round(1.6);
- 求x的y次幂pow(x,y) select pow(2,3);
- 获取圆周率PI() select PI();
- 随机数rand(),值为0-1.0的浮点数 select rand();
日期时间函数
year(date)返回date的年份(范围在1000到9999)
month(date)返回date中的月份数值
day(date)返回date中的日期数值
hour(time)返回time的小时数(范围是0到23)
minute(time)返回time的分钟数(范围是0到59)
second(time)返回time的秒数(范围是0到59)
select year('2016-12-21');
select date_format('2016-12-21','%Y %m %d');
/*当前日期current_date()*/
select current_date();
/*当前时间current_time()*/
select current_time();
/*当前日期时间now()*/
select now();
视图
对于复杂的查询,在多次使用后,维护是一件非常麻烦的事情,视图本质就是对查询的一个封装,类似Javascript中的function一样,对某一个功能的封装
/*定义视图*/
create view stuscore as
select students.*,scores.score from scores
inner join students on scores.stuid=students.id;
/*视图的用途就是查询*/
select * from stuscore;
事务
当一个业务逻辑需要多个sql完成时,如果其中某条sql语句出错,则希望整个操作都退回,使用事务可以完成退回的功能,保证业务逻辑的正确性
银行转账是经典的解释事务的例子。用户A给用户B转账5000元主要步骤可以概括为如下两步。
第一,账户A账户减去5000元;
第二,账户B账户增加5000元;
这两步要么成功,要么全不成功,否则都会导致数据不一致。
事务四大特性(简称ACID)
- 原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么均不执行
- 一致性(Consistency):几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致
- 隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的
- 持久性(Durability):对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障
事务语句
开启begin;
提交commit;
回滚rollback
乐观锁和悲观锁
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。