Bootstrap

数据库的简单学习

数据库简介

关系型数据库:Mysql 、Oracle 、SqlServer… DB2 PG 达梦

非关系型数据库:Redis 、MongoDB…

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。

MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库。

SQL(Structured Query Language)

结构化查询语言

SQL包括了所有对数据库的操作,主要是由4个部分组成:

1.数据定义:又称为“DDL语言”,定义数据库的逻辑结构,包括定义数据库、基本表、视图和索引4部分。

2.数据操纵:又称为“DML语言”,包括插入、删除和更新三种操作。

3.数据查询:又称为“DQL语言”,包括数据查询操作。

4.数据控制:又称为“DCL语言”,对用户访问数据的控制有基本表和视图的授权及回收。

5.事务控制:又称为“TCL语言”,包括事务的提交与回滚。

Mysql的下载与安装

登录数据库

mysql -u root -p root

Mysql简单命令:

查询所有数据库:

show databases;

选择使用数据库:

use 数据库名称;

创建数据库:

create database 数据库名称;

删除数据库:

drop database 数据库名称;

查看数据库编码

show create database 数据库名称;

查看当前数据库下面所有的表格:

show tables;

创建表格:

create table 表名称 (字段 字段类型(长度));

create table 表名称 (字段 字段类型(长度),字段 字段类型(长度),字段 字段类型(长度)........);

create table user (id int(3),name varchar(10));

create table person (id int(4),name varchar(10),phone varchar(11),address varchar(30));

查看表结构:

desc user;

desc 表名称;

删除表格:

drop table user;

drop table 表名称;

给表格中添加数据:

 insert into person values (1,"admin","13988888888","taiyuan");//全字段

 insert into person(id,name) values (1,“张三”)
 若表名后面什么也不写,values后面则写全字段,按顺序来,字段类型不能乱

若指定添加,则在表名称后面写清楚要添加的字段,同时values后面要和字段相对应

 insert into 表格名称 values (字段1,字段2....);

查询表格中所有数据

 select * from person;

修改表结构:(选)

语法:(修改表字段名)

 ALTER TABLE 表名称 CHANGE 原列名 想改成的列名 列类型;

ALTER TABLE test  CHANGE id  idd  INT(10);

修改表名字:

语法:1

 ALTER TABLE 原表名称  rename  想改成的表名称;

alter table test  rename testt;

语法:2

RENAME TABLE 原表名称 TO 想改成的表名称;

RENAME TABLE test TO testt;

 

修改字段类型:(一般不修改字段类型)

如varchar 修改成 int

Update 表名称 set 要修改的字段 = null  //一定要赋值为null 不能是空字符串

alter table 表名称modify column 修改的字段名称 要修改成的字段类型(长度) ;

update  user  set name=null

alter table user  modify column  name  int(20) ;

 

 

增加字段

alter table 表名 add字段 类型(长度);

alter table user add phone int(11);

删除字段

alter table 表名 drop 字段名 

alter table user drop phone;

MySQL是一种关系型数据库管理系统,它支持多种数据类型,包括整数、浮点数、定点数、字符串、二进制和日期/时间类型。在本文中,我们将列出MySQL中所有的字段类型,并解释每种类型的含义、所占用的字节、存储范围、最大存储值以及使用场景。

整数类型包含(TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT),适用于存储整数,如用户ID、年龄等。

浮点数类型(FLOAT、DOUBLE),适用于存储小数,如商品价格、订单金额等。

定点数类型(DECIMAL),适用于存储精度要求高的数值,如货币金额等。

字符串类型(CHAR、VARCHAR、TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT),适用于存储文本数据,如用户名、地址等。

二进制类型(BINARY、VARBINARY、TINYBLOB、BLOB、MEDIUMBLOB、LONGBLOB),适用于存储二进制数据,如图片、音频等。

日期和时间类型(DATE、TIME、DATETIME、TIMESTAMP),适用于存储日期和时间相关的数据,如订单创建时间、用户注册时间等。

CHAR与VARCHAR的区别

1.CHAR是定长的,范围是0~255,char会开辟固定的长度,值超出范围将被截短,值小于范围的用空格填充。

2.VARCHAR是可变长度,范围0~65535,varchar是数据占多长就多长,不会来填补,但是会多一个字节来存储其字符的长度

3.它们之间的不同处在于MySQL数据库处理指示器的方式,CHAR把这个大小视为值的大小,在长度不足的时用空格补足。而VARCHAR类型把它是为最大值,并且只存储字符串实际需要的长度(增加一个额外字节来存储字符串本身的长度)来存储值,所以短于指示器长度的VARCHAR类型不会被空格填补,但长于指示器的值仍然会被截短。

4.VARCHAR类型可以根据实际内容动态改变存储值的长度,因此在不能确定字段需要多少字符时使用VARCHAR类型可以有效地节约磁盘空间、提高存储效率。

5.CHAR的存储方式是,对英文字符(ASCII)占用1个字节,对一个汉字占用两个字节;

6.VARCHAR的存储方式是,对每个英文字符占用2个字节,汉字也占用2个字节,两者的存储数据都非unicode的字符数据。

SQL中的增删改查

增加:

insert into person values (1,"admin","13988888888","taiyuan");

insert into person (id) values (1);

insert into 表格名称 values (字段1,字段2....);

 

删除:

delete from person where id = 1; 指定条件删除

delete from person; 清空表格

 

修改:

update person set name = "admin" where id = 3;

update person set name = "admin001";

 

查询:

select * from person;

select * from person where id = 4;

数据库中的约束

在创建表格的过程中可以给某些字段追加约束条件

非空约束 NOT NULL

NK

create table t_user (

​	id int(3) not null,

​	username varchar(10),

​	password varchar(15)

);

 

唯一约束 UNIQUE

UK

create table t_user (

​	id int(3) not null,

​	username varchar(10) unique,

​	password varchar(15)

);

 

 

create table t_user (

​	id int(3) not null,

​	username varchar(10),

​	password varchar(15),constraint UK_username unique(username)

);

主键约束 PRIMARY KEY

主键(PRIMARY KEY),也称“主键约束”。

MySQL主键约束是一个列或者多个列的组合,其值能唯一地标识表中的每一行。这样的一列或多列称为表的主键,通过它可以强制表的实体完整性。主键主要是用于其他表的外键关联,以及本记录的修改与删除。

主键(PRIMARY KEY)是 MySQL 中使用最为频繁的约束。一般情况下,为了便于 DBMS 更快的查找到表中的记录,都会在表中设置一个主键。

PK  效果上 == 非空约束+唯一约束

create table t_user (

​	id int(3),

​	username varchar(10),

​	password varchar(15),constraint pk_id primary key(id)

);

联合主键

MYSQL是一个关系型数据库管理系统,其中联合主键是一种非常重要的数据库设计概念。在MYSQL中,联合主键是指使用多个列值来唯一标识一个记录的主键。一个联合主键可能包含两个或更多个字段,而这些字段一起组成了一个唯一标识符。这样可以保证在数据表中每个记录都有唯一的标识。

外键约束 FOREIGN KEY(选修)

一对一 一对多 多对多

FK 用到两张表格

t_user (一)

t_book (多)

关系维护在(多)方

uidUsernamepassword
1Lufeilufei
2Qiaobaqiaoba
bidBooknameauthoru_id(外键)
1笑傲江湖金庸1
2神雕侠侣金庸2
3鹿鼎记金庸2
4连城诀金庸2
创建过程中分两步进行:

指定哪一个字段是外键  foreign key(u_id)

外键需要引用哪一个表格的字段  references t_user(id)

create table t_user (

​	id int(3),

​	username varchar(10),

​	password varchar(15),constraint pk_id primary key(id)

);

create table t_book (

​	bid int(3),

​	bookname varchar(6),

​	author varchar(3),

​	u_id int(3),constraint pk_bid primary key(bid),constraint fk_u_id foreign key(u_id) references t_user(id)

);

一级菜单 二级菜单 自关联

设计一张菜单表:

idnameurloneid
1用户管理XXX
2用户添加XXX1
3用户删除XXX1
4用户查询XXX1
5用户修改XXX1
6商品管理XXX
7商品上架XXX6
8商品下架XXX6
create table t_menu (

​	id int(3),

​	name varchar(10),

​	url varchar(20),

​	oneid int(3),constraint pk_id primary key(id),constraint fk_oneid foreign key(oneid) references t_menu(id)

);

外键状态下的级联操作:

级联删除谨慎使用

create table t_book (

​	bid int(3),

​	bookname varchar(6),

​	ahthor varchar(3),

​	u_id int(3),constraint pk_bid primary key(bid),constraint fk_u_id foreign key(u_id) references t_user(id) on delete cascade

);

 

create table t_book (

​	bid int(3),

​	bookname varchar(6),

​	ahthor varchar(3),

​	u_id int(3),constraint pk_bid primary key(bid),constraint fk_u_id foreign key(u_id) references t_user(id) on delete set null

);

检查约束 CHECK

在一个范围中间

create table test32(

id number primary key,

age number check(age>0 and age<120)

);

数据库三范式

第一范式(1NF)

第一范式主要是保证数据表中的每一个字段的值必须具有原子性,也就是数据表中的每个字段的值是不可再拆分的最小数据单元

第二范式(2NF)

第二范式要求在满足第一范式的基础上,还要满足数据表里的每一条数据记录,都是可唯一标识的,而且所有的非主键字段,都必须完全依赖主键,不能只依赖主键的一部分。

第三范式(3NF)

第三范式建立在已经满足第二范式的基础上

数据表中的每一个非主键字段都和主键字段直接相关

查询机制

emp员工表

字段描述类型
empno员工编号mediumint
ename员工姓名varchar
job职位varchar
mgr领导编号mediumint
hiredate入职日期date
sal工资decimal
comm奖金decimal
deptno部门编号mediumint

dept部门表

字段描述类型
deptno部门编号mediumint
dname部门名称varchar
loc部门位置varchar

salgrade工资等级

字段描述类型
grade等级mediumint
losal最低工资decimal
hisal最高工资decimal
简单查询
查询所有员工信息

SELECT * from emp;

查询所有并起别名

SELECT empno '员工编号',ename '员工姓名',job '职位',mgr '领导编号' from emp;

SELECT e.empno,e.job,e.sal from emp e;

查询公司中的职位

SELECT  DISTINCT job from emp;

DISTINCT :去重关键字

限定查询

SELECT * FROM 表名称 [限定条件]Where  >  <  >=  <=  !=  between...and...  and  or  is null  in  like  ...

查询工资高于1500的所有员工信息

SELECT * from emp WHERE sal > 1500;

查询工资高于1500低于3000的所有员工信息

SELECT * from emp WHERE sal >= 1500 and sal <= 3000;

//between...and...取的区间值

SELECT * from emp WHERE sal BETWEEN 1500 and 3000;

 

查询没有奖金的所有员工信息  or或者

SELECT * from emp where comm = 0 or comm is NULL;

查询有奖金的员工信息

SELECT * from emp where comm > 0;

查询员工姓名中带有S的员工信息

SELECT * from emp where ename like '%S%';

模糊匹配:

%:占位符 代表0个或者多个字符

_:占位符  代表一个字符

查询入职日期在1981年的员工

SELECT * from emp where hiredate BETWEEN '1981-01-01' and '1981-12-31';

SELECT * from emp where hiredate LIKE '%1981%';

查询员工编号在7499  7521  7566 in包含

SELECT * from emp where empno in (7499,7521,7566);

排序查询

SELECT * FROM 表名称 [限定条件][排序条件]Order by 字段 升序/降序  升序 asc降序 desc

根据工资由高到底进行排序查询

SELECT * from emp order by sal desc;

如果工资一样,那么按照入职日期升序

SELECT * from emp order by sal desc,hiredate asc;
多表查询
查询所有员工的详细信息(包含部门信息)

select * from emp,dept; (有问题的查询)

带来的问题是,简单对两张表做乘积处理,形成大量冗余数据,这种现象叫做笛卡尔积效应

需要追加两张表的关联条件,***\*从显示上\****消除笛卡尔积效应

select * from emp,dept where emp.deptno = dept.deptno;

查询员工编号,员工姓名,员工职位,员工工资,部门名称,部门位置

逐步分析:

先确定需要的表

emp e,dept d

确定需要的字段

e.empno,e.ename,e.job,e.sal,d.dname,d.loc

确定关联条件

e.deptno = d.deptno

select e.empno,e.ename,e.job,e.sal,d.dname,d.loc from emp e,dept d where e.deptno = d.deptno;
查询所有的员工编号,员工姓名,员工职位,领导姓名,领导职位

先确定需要的表

emp e1,emp e2

确定需要的字段

e1.empno 员工编号,e1.ename 员工姓名,e1.job 员工职位,e2.ename 领导姓名,e2.job 领导职位

确定关联条件

e1.mgr = e2.empno

select e1.empno 员工编号,e1.ename 员工姓名,e1.job 员工职位,e2.ename 领导姓名,e2.job 领导职位 from emp e1,emp e2 where e1.mgr = e2.empno;

发现少一条记录,如果要解决这个问题,需要借助连接查询
连接查询
SELECT * FROM 表名称 [连接查询][限定条件][排序条件]左(外)连接  left (outer) join...on 条件右(外)连接  right (outer) join...on 条件

查询所有的员工编号,员工姓名,员工职位,领导姓名,领导职位

select e1.empno 员工编号,e1.ename 员工姓名,e1.job 员工职位,e2.ename 领导姓名,e2.job 领导职位 from emp e1 ***\*left join\**** emp e2 ***\*on\**** e1.mgr = e2.empno;
分组查询

分组前提:需要分组的列出现了重复数据

SELECT * FROM 表名称 [连接查询][限定条件][分组查询][排序条件]Group by 字段

语法限制:

  1. 一旦出现分组,那么select后边只允许出现统计函数以及分组字段
  2. 统计函数可以单独使用
  3. 如果出现统计函数的嵌套,那么select后边只允许出现统计函数
求每个部门的平均工资

select deptno,avg(sal) from emp group by deptno;

select emp.deptno,dept.dname,avg(sal) from emp,dept where emp.deptno = dept.deptno group by emp.deptno,dept.dname;

通过右连接将没有展示的数据进行展示:

select dept.deptno,dept.dname,avg(sal) from emp right join dept on emp.deptno = dept.deptno group by emp.deptno,dept.deptno,dept.dname;

展示平均工资高于2000的部门信息

*错误写法*

select dept.deptno,dept.dname,avg(sal) from emp right join dept on emp.deptno = dept.deptno group by emp.deptno,dept.deptno,dept.dname where avg(sal) > 2000;

解决办法:

如果在分组之后需要再次筛选,不可以使用where,需要使用Having

select dept.deptno,dept.dname,avg(sal) from emp right join dept on emp.deptno = dept.deptno group by emp.deptno,dept.deptno,dept.dname *having* avg(sal) > 2000;

HAVING 关键字和 WHERE 关键字都可以用来过滤数据,且 HAVING 支持 WHERE 关键字中所有的操作符和语法。

但是 WHERE 和 HAVING 关键字也存在以下几点差异:

1.一般情况下,WHERE 用于过滤数据行,而 HAVING 用于过滤分组。

2.WHERE 查询条件中不可以使用聚合函数,而 HAVING 查询条件中可以使用聚合函数。

3.WHERE 在数据分组前进行过滤,而 HAVING 在数据分组后进行过滤 。

4.WHERE 针对数据库文件进行过滤,而 HAVING 针对查询结果进行过滤。也就是说,WHERE 根据数据表中的字段直接进行过滤,而 HAVING 是根据前面已经查询出的字段进行过滤。

5.WHERE 查询条件中不可以使用字段别名,而 HAVING 查询条件中可以使用字段别名。

单行函数查询

在MySQL中,单行函数是一种对单个输入值执行操作的函数。它接受一个输入参数并返回一个值。单行函数可以用于处理数据,并在查询中进行数据转换、计算、日期和时间处理等操作。

以下是MySQL中常见的单行函数示例:

字符串函数:

CONCAT:连接两个或多个字符串。

SUBSTRING:返回字符串的子串。

LENGTH:返回字符串的长度。

LOWER:将字符串转换为小写。

UPPER:将字符串转换为大写。

数值函数:

ABS:返回数值的绝对值。

CEIL:返回大于或等于给定数值的最小整数。

FLOOR:返回小于或等于给定数值的最大整数。

RAND:返回一个随机数。

日期和时间函数:

CURDATE:返回当前日期。

CURTIME:返回当前时间。

NOW:返回当前日期和时间。

DATE_FORMAT:按照指定格式格式化日期或时间。

条件函数:

IF:根据条件返回不同的值。

CASE:根据条件执行不同的操作。

其他函数:

MD5:计算字符串的MD5哈希值。

SHA1:计算字符串的SHA1哈希值。

REVERSE:反转字符串的顺序。

TRIM:删除字符串开头和结尾的空格或指定字符。

子查询

Where子查询 单行单列 多行单列

Form子查询 多行多列

查询比SMITH工资高的人

select * from emp where sal > (select sal from emp where ename = 'SMITH');

查询比平均工资高的人

select * from emp where sal > (select avg(sal) from emp);

查询和经理工资相同的员工信息

select * from emp where sal in (select sal from emp where job = 'MANAGER');
查询部门编号,部门位置,部门人数,部门平均工资

第一步:查询每个部门的编号,名称,位置

Dept d

第二步:统计部门人数,平均工资

emp e

e.deptno deptno, count(e.empno) num,avg(e.sal) sal

Group by e.deptno

select e.deptno deptno, count(e.empno) num,avg(e.sal) sal from emp e Group by e.deptno;

 

将查到的数据和dept组合

select temp.deptno,temp.num,temp.sal,d.dname,d.loc from (select e.deptno deptno, count(e.empno) num,avg(e.sal) sal from emp e Group by e.deptno) temp,dept d where temp.deptno = d.deptno;

通过右连接处理边界数据

select d.deptno,IFNULL(temp.num,0) 部门人数 ,IFNULL(temp.sal,0) 平均工资 ,d.dname,d.loc from (select e.deptno deptno, count(e.empno) num,avg(e.sal) sal from emp e Group by e.deptno) temp right join dept d on temp.deptno = d.deptno;

IFNULL() 函数用于判断第一个表达式是否为 NULL,如果为 NULL 则返回第二个参数的值,如果不为 NULL 则返回第一个参数的值。

分页查询

LIMIT 关键字 参数 参数1为索引值从哪开始,第二个参数为每页显示几个

SELECT * FROM product LIMIT 30;// 从0开始,显示30条

SELECT * FROM product LIMIT 10,10;//从10开始 显示10条

由此,我们可以分析出分页查询的SQL语句格式

*select * from my_book limit (page-1)pageSize,pageSize;

其中,page是页码,pageSize是每页显示的条数

当数据库中数据量较大时,使用limit函数会存在性能问题,我们可以用主键来代替limit函数实现数据分页查询

select * from my_book where id > (page-1)*pageSize limit pageSize;

select * from my_book where id > 10 limit 5;

事务处理

概念:在一个业务逻辑中包含多个步骤操作,需要被事务进行管理,要么同时成功,要么同时失败

默认提交事务

关闭默认提交事务:set autocommit = 0;

手动提交:commit

手动回滚:rollback

开启默认提交事务:set autocommit = 1;

事务的四大特性(掌握)

1、*原子性*:事务包含的所有数据库操作要么全部成功,要不全部失败回滚

2、*一致性*:一个事务执行之前和执行之后都必须处于一致性状态。拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。

3、*隔离性*:一个事务未提交的业务结果是否对于其它事务可见。级别一般有:read_uncommit,read_commit,read_repeatable,串行化访问。

4、*持久性*:一个事务一旦被提交了,那么对数据库中数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。(持久化操作)

事务的隔离级别(了解)

Read uncommitted 读未提交

产生问题:脏读、不可重复读、幻读

提供了事务建最小限度的隔离。顾名思义,就是一个事务可以读取另一个未提交事务的数据。

示例:小明去商店买衣服,付款的时候,小明正常付款,钱已经打到商店老板账户,但是小明发起的事务还没有提交。就在这时,商店老板查看自己账户,发现钱已到账,于是小明正常离开。小明在走出商店后,马上回滚差点提交的事务,撤销了本次交易曹邹。

结果:小明未付钱买到了衣服,商店老板实际未收到小明的付款。

分析:商店老板查看自己的资金账户,这个时候看到的是小明还没有提交事务的付款。这就是脏读。

注意:处于该隔离级别的事务A与B,如果事务A使用事务B不提交的变化作为计算的基础,然后哪些未提交的变化被事务A撤销,这就导致了大量的数据错误变化。

Read committed 读已提交(Oracle数据库默认的隔离级别)

产生问题:不可重复读、幻读

处于Read committed (读已提交)级别的事务可以看到其他事务对数据的修改。也就是说,在事务处理期间,如果其他事务修改了相应的表,那么同一个事务的同一sql在其他事务执行前后返回的是不同的结果。一个事务要等另一个事务提交后才能读取数据。

示例:小明卡里有1000元,准备与几个朋友聚餐消费,消费1000元,当他买单时(事务开启),收费系统检测到他卡里有1000元。就在检测完毕的时候,小明女朋友发现小明有私房钱,全部转走并提交。当收费系统准备扣款时,再检查小明卡里的金额,发现已经没钱了,付款不成功。小明此时就会很纳闷,明明有钱的呀,钱呢?

分析:该示例中同一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。该隔离级别可以解决脏读问题。

Repeatable read 可重复读(Mysql数据库默认的隔离级别)

产生问题:幻读

在开始读取数据(事务开启)时,不再允许修改操作

示例:还是小明有1000元,准备跟朋友聚餐消费这个场景,当他买单(事务开启)时,收费系统检测到他卡里有1000元,这个时候,他的女朋友不能转出金额。接下来,收费系统就可以扣款成功了,小明醉醺醺的回家,准备跪脱衣板。

分析:重复读可以解决不可重复读的问题,这句话有些别扭,大家可以仔细品一下。

写到这里,大家可能会产生疑问,什么情况下产生幻读呢?

示例来了:

小明在公司上班,女朋友告诉他,拿着他的卡去逛街消费。花了一千元,然后小明去查看他银行卡的消费记录(事务开启),看到确实是花了一千元。就在这个时候,小明女朋友又花三千元买了一些化妆品和衣服,即新增了一些消费记录。当小明打印自己银行卡消费记录单的时候(女朋友事务提交),发现花了四千元,似乎出现了幻觉,小明很心疼。这就是幻读

Serializable 串行化

解决所有问题

注意点:

隔离级别越高,性能越低

查询数据库的默认隔离级别:

select @@tx_isolation;

改变数据库的隔离级别:

修改全局

set global transaction isolation level 隔离级别关键字;

修改回话

//设置read uncommitted级别:

set session transaction isolation level read uncommitted;

//设置read committed级别:

set session transaction isolation level read committed;

//设置repeatable read级别:

set session transaction isolation level repeatable read;

//设置serializable级别:

set session transaction isolation level serializable;

开启事务:

Start transaction

Update person set sal = sal - 500 where id = 1;

Update person set sal = sal + 500 where id = 2;

;