mysql学习笔记(动力节点)

发布时间 2023-05-04 12:02:58作者: hangsingplus

1.连接数据库

1.1命令行连接

mysql -uroot -p123456 -- 连接
flush privileges; -- 刷新权限
-- 所有的命令都采用分号结尾,切换不需要
show databases; -- 查看所有的数据库
mysql> use school -- 切换数据库:use+数据库名
Database changed

show tables; -- 查看数据库所有的表
describe students; -- 查看表的信息

create database newdatabase; -- 创建一个数据库

exit; -- 退出连接 //注意分号结束一个语句

-- 单行注释
/*
多行注释
*/
-- 修改登录密码,登陆之后输入:
-- set password for username @localhost = password(newpwd);
-- 其中 username 为要修改密码的用户名,newpwd 为要修改的新密码
-- 再推出即可登入
set password for root @localhost = password('root');  -- 新密码为root

1.2数据库 xxx 语言

DDL 对表结构增删改

DML 对表中数据增删改

DQL 查询

DCL 数据控制

TCL 事物控制

写命令行的地方:

点击【工具】菜单,选择【命令列界面】

2.操作数据库

操作数据库 > 操作数据库中的表 > 操作数据库中表的数据

mysql关键字不区分大小写

2.1操作数据库

2.1.1创建数据库

-- 为mysql语句
create database [if not exists] west 

2.1.2删除数据库

drop database [if exists] west

2.1.3使用数据库

use school -- 如果表名或字段名是一个特殊字符或者系统带的变量名字,需要在使用的名字左右加上Tab见上方的符号
-- e.g.
select `user` from student;

2.1.4查看数据库

--查看当前使用的是哪个
show databases;
-- 或:
select database;
-- 查看mysql的版本号
select version();

2.1.5查看其它库中的表

show tables from databases;

2.1.6查看表的结构/创建语句

decs table name;
show create table <table name>;

2.1.8 退出数据库

exit;

2.2 条件限制查询

select 字段 from 表名 where 条件;
    -- 若字段部分为*,证明查询所有内容,但速度较慢,JDBC中一般不用

2.2.1 and / or

and 优先级高于or,若一起使用记不清优先级时,可使用括号

2.2.2 between … and …

等同于 >= and <=

可用于字符串和数字,都是闭区间

2.2.3 in

in 等同于多个 on

select ename,job from emp where sal in (800,5000); -- 注意in后边不是区间,而是具体的值

not in : 不是800和5000的

2.2.4 模糊查询 like

需掌握两个符号:

% : 多个字符 _ : 一个字符

比如找出名字里含O的:

select ename from emp where ename like '%O%';

找出名字里第二个字母为A的

select ename from emp where ename like '_A%';

找出名字里第三个字母为A的

select enmae from emp where ename like '__A';

找出名字里有下划线的

select enmae from emp where ename like '%_%';

因为‘_’表示任意一个字符,这样写会查询到所有名字,应该用转义字符:

select enmae from emp where ename like '%/_%';

找出名字中最后一个字是T的:

select ename from emp where ename like '%T';

2.3 排序(升序、降序)

2.3.1 单个字段

按照工资升序,找出员工名字和工资

select 
	ename,sal
from
	emp
order -- 排序
	by -- 通过
 		sal; -- 工资

注意,默认为升序

若需指定:升序 asc 降序 desc

select ename,sal from emp order by sal asc;
select ename,sal from emp order by sal desc;
select ename,sal from emp order by sal;

2.3.2 多个字段

越靠前的字段起的主导作用越大,只有当前面的字段无法完成排序时,才会启用后面的字段。

按照工资降序,若工资相等,按照名字升序排列。找出员工名字和工资:

select enmae,sal from emp order by sal desc,eame asc;

找出工作岗位是salesman的员工,并且按工资降序排列

select 
	ename,job,sal
from
	emp
where
	job='salesman'
order by
	sal 
		desc;

2.4 分组函数 (group function)

2.4.1 一共五个函数

属于多行处理函数 : 输入多行,输出一行

count 计数

sum 求和

avg 平均值

max 最大值

min 最小值

对于某一组数据(字段)操作

e.g 找出工资总和

select sum(sal) from emp;

2.4.2 单行处理函数

输入n行,输出n行,以ifnull()函数示例

前提:所有数据库中只要有null参与的运算,其最后结果一定是null,但所有分组函数自动忽略null.

引入:ifnull()空处理函数

ifnull(可能为空的数据,被当作什么处理)

e.g

select ename,ifnull(comm,0) as comm from emp;
select ename,(sal+ifnull(comm,0))*12 as yearsal from emp;

2.4.3 分组函数使用的语法规则

分组函数不可直接使用在where子句当中(下边解释)

count(*)和count(具体的某个字段)的区别:

​ count(*):不是统计某个字段中数据的个数,而是统计总记录条数。(和某个字段无关)

​ count(comm):表示统计comm字段中不为NULL的数据的总数量。

2.5 分组查询group by

group by:按照某个字段或某些字段进行分组

having:对分组之后的数据进行再次过滤

​ 两个搭配使用

案例:找出每个工作岗位的最高薪资

select max(sal) from emp group by job;
-- 先分组再找最大值

注意:分组函数一般都会和group by联合使用,且分组函数都是在group by结束之后才执行的,而group by在where

之后执行,所以分组函数不能在where中使用(相当于还未分组,不能使用分组函数)

当一句sql语句没有group by语句时,整张表的数据自成一组

当一句sql语句有group by语句时,select后边跟着的字段只能是分组函数和参与分组的字段,否则报错或结果不正确(Oracle比mysql语法规则严谨)

2.6分组之后再次过滤

用 having 还是 where ?

-- 找出薪资大于2900的部门
select deptno,max(sal) from emp group by deptno having max(sal) > 2900;
-- 这种方式效率低,分组后又舍弃数据,此时应使用where先过滤掉小于2900的再进行分组(基于where比group by先执行
select deptno,max(sal) from emp where sal > 2900 group by deptno; 
-- 效率较高,能使用where过滤的尽量使用where,涉及到求平均等分组函数的情况则只能用having

3.DQL语句

总结:以上为单表查询,接下来是多表查询

3.1执行顺序:

select

​ ..

from

​ ..

where

​ ..

having

​ ..

order by

​ ..

3.2 查询结果集的去重

-- 在字段前加distinct(截然不同的,完全分开的;清晰的)
select distinct job from emp;

注意:distinct:只能出现在所有字段的前面,且对后边的所有字段联合去重

3.3 连接查询

定义:多张表共同查询出最终的结果

3.3.1 连接查询的分类

根据表的连接方式:

​ 内连接:

​ 等值连接

​ 非等值连接

​ 自连接

​ 外连接:

​ 左外连接(左连接)

​ 右外连接(右连接)

​ 全连接

笛卡尔乘积现象:若未对连接查询的多张表的字段进行条件限制,最后的查询结果为多张表字段数量的乘积。

但是,加条件过滤避免了笛卡尔积现象也不能减少底层记录的匹配次数,只是显示出来的减少了。

3.3.2 给表起别名

select e.ename,d.dname from emp e,dept d;-- as或者空格都可以

起别名的好处:效率高(防止多张表有字段相同,需得访问多遍)、可读性好

3.3.3 内连接

等值连接:查询条件是等量关系

e.g查询每个员工的部门名称 (join on语句)

-- sql99语法结构更清晰,将查询条件与过滤条件where分离
select
	e.ename,d.dname
from 
	emp
inner join -- inner可以省略,带着可读性更好些(表示内连接)
	dmp
on 
	e.dptno = d.dptno;
where...

非等值连接:查询条件不是等量关系

select
	e.ename,e.salary,s.grade
from 
	emp
inner join -- inner可以省略,带着可读性更好些(表示内连接)
	dmp
on 
	e.salary btween s.lsal and s.higsal; -- 非等量关系
where...

自连接:一张表看作两张表,自己连自己。

e.g找出每个员工的上级领导,要求显示员工名和对应的领导名

将两张表视作员工表和领导表,员工的领导编号=领导的员工编号时即找出对应关系

select 
	a.enamem as '员工名',b.ename as '领导名'
from
	emp a
inner join
	emp b
on -- 条件
	a.mgr = b.empno;

3.3.4 外连接(使用的多)

3.3.4.1 与内连接区别

内连接:A和B表进行连接,将两个表能够匹配上的记录查询出来。A、B表没有主副之分,是平等的。

外连接:AB两表中一主表一副表,主要查询主表中的数据,捎带查询附表,若副表中的数据没有和主表中的数据匹配上,副表自动模拟出null与之匹配。特点:主表的数据无条件的全部查询出来。

比如查员工领导,大boss也是员工,虽然没有领导但也不能丢失数据,要查出来的。

3.3.4.2 分类

左外连接(左连接):表示左边的表使主表。

右外连接(右连接):表示右边的表使主表。

两种连接写法不同。

-- 左外连接,左表占主导地位
select 
	a.enamem as '员工名',b.ename as '领导名'
from
	emp a
left outer join -- outer可省略
	emp b
on -- 条件
	a.mgr = b.empno;
-- 右外连接,右表占主导地位
select 
	a.enamem as '员工名',b.ename as '领导名'
from
	emp b -- 两表交换位置,等效
right join
	emp a
on -- 条件
	a.mgr = b.empno;

3.3.5 三张表以上的连接

找出每一个员工的部门名称、工资等级和上级领导。

员工和部门名称、工资等级内连接,和上级领导左连接,嵌套查询

select e.ename as '员工',d.name,s.grade,e1.ename '领导' 
from
	emp e 
join 
	dept d 
on 
	e.deptno = d.deptno
join 
	salgrade s
on
	e.sal between s.losal and s.hisal 
left join 
	emp e1
on 
	e.mgr = e1.empno;

3.4 子查询

3.4.1 where子句中使用子查询

找出高于平均薪资的员工信息

-- 第一步:找出平均薪资
select avg(sal) from emp;
-- 第二步:where过滤
select * from emp where sal > 2073.21;
-- 第一二步合并:
select * from emp where sal > (select avg(sal) from emp);

3.4.2 from子句中使用子查询

找出每个部门平均薪水的薪资等级

-- 一:找出每个部门的平均薪水
select deptno,avg(sal) as avgsal from emp group by deptno;
-- 二:将以上查询结果当作临时表t,让t和salgrade表连接查询,条件是t.avgsal 在其薪资范围之间
select 
	t.*,s.grade
from
	(select deptno,avg(sal) as avgsal from emp group by deptno) t
join 
	salgrade s
on 
	t.avgsal between s.losal and s.higsal;

找出每个部门平均的薪资等级

-- 一:找出每个员工的薪水等级
select e.name,e.sal,e.deptno,s.grade from emp join salgrade on e.sal between s.loasal and s.higsal;
-- 二:基于以上结果继续按照部门分组,求薪水等级的平均值
select 
	e.deptno,avg(s.grade) -- 基于以上查询出的等级结果求每个组的平均值
from 
	emp 
join 
	salgrade 
on 
	e.sal between s.loasal and s.higsal
group by -- 没有必要作临时表,继续往下写效率更高
	e.deptno;

3.4.3 select后边嵌套子查询

找出每个员工所在的部门名称,要求显示员工姓名和部门名

-- 之前学的:
select e.ename,d.dname from emp e join dept d on e.deptno = d.deptno;
-- 直接在select后边嵌套子查询
select e.ename,e.deptno,(select d.dname from dept d where d.deptno = e.deptno) as dname from emp e;

3.5 union(可以将查询结果相加)

找出工作岗位是a和b的员工

-- 一:
select e.ename,job from emp e where job = 'a' or job = 'b';
-- 二:
select e.ename,job from emp e where job in('a','b'); -- in相当于多个on,是值不是区间
-- 三:union
select e.ename,job from emp e where job = 'a'
union
select e.ename,job from emp e where job = 'b';

union可以将不同表中的数据拼接到一起,但两个字段的列数需一致

3.6 limit(分页查询用)

mysql特有

作用:取结果集中的部分数据

3.6.1 语法机制

limit startIndex,length; -- startIndex起始位置,length取几个长度,注意start是开区间,不包括起始位置

-- 比如,取工资前五名的员工
select ename,sal from emp order by sal desc limit 0,5;

3.6.2 Limit是sql语句最后执行的一个环节

4.DML语句 只操作表中的数据

4.1 表的创建

4.1.1 表的基本数据类型

varchar:可变长字符串

data:日期类型

BLOB:二进制大对象(存储图片、视频等流媒体信息)

CLOB:字符大对象(存储较大文本,比如,可以存储较大的字符串)

e.g 创建一个学生表

create table t_student(
-- 先写变量名再加数据类型
	no bigint,
	name varchar(266),
	sex char(1) default 1, -- 默认性别的值为1
	classno varchar(),
	birth char(10),
);

4.1.2 insert 语句插入数据

第一种方式

语法格式:

insert into 表明(字段名1,2,3,4) values(值1,2,3,4);
注意:字段的数量和数据类型与值的数量和数据类型一一对应

insert into t(no,name,sex) values(1,'Marry','0');
-- 注意数据库用的utf-8,dos命令窗口采用的GBK,输入中文会出现乱码

需要注意的地方:

​ 当一条inser语句执行成功之后,表中必然会多一行记录,而新加的记录即使某些字段是NULL(未输入,系统自动指配),后面也没法用insert语句插入数据了,只能用update更新

第二种方式

insert into t_student values(值。。。)

这种方法输入的值必须和列数匹配

第三种方式 -- 一次插入多行数据

插入多行顺序时不用写字段名字,但要确保值的顺序与表中的列顺序相同

insert into t_student values(值。。。),(值。。。)

4.2 表的复制以及批量插入

表的复制:

create table emp2 as select * from emp;
-- 将查询语句作为表创建出来

将查询结果插入到一张表中:

insert into dept1 select * from dept;

4.3 修改表中的数据 ---- update

语法格式:

​ update 表名 set 字段名1=值1,字段名2=值2.。。。where 条件;

没有条件,整张表的数据全部更新

4.4 删除数据

语法格式:

​ delete from 表名 where 条件;

没有条件,整张表的数据全部删除

删除一行:

delete from dept where deptno=10;

删除大表(重点):

delete :时间很长,效率慢,原因:没有释放真实的存储空间,可以找回delete删掉的数据

表截断 truncate:风险较高的不能后悔的方法

5 DDL语句

5.1关于表结构的修改

很少发生,用工具,出现在java中的sql:insert delete update select (对表中的数据操作)

增删改查术语:CRUD(各取首字母)Create(增) Retrieve(检索) Update(修改) Delete(删除)

drop: alter table 表名 drop 字段

​ drop table

1、drop是DDL,会隐式提交,所以,不能回滚,不会触发触发器。

2、drop语句删除表结构及所有数据,并将表所占用的空间全部释放。

3、drop语句将删除表的结构所依赖的约束,触发器,索引,依赖于该表的存储过程/函数将保留,但是变为invalid状态。

5.2 查看表结构的信息

1.desc查看表结构的详细信息

desc table_name;
-- PS:此处desc是describe的缩写,用法: desc 表名/查询语句 

2.desc降序排列数据

select ename,sal from emp order by sal desc; 
手动指定按照薪水由大到小排序(降序关键字desc) 
select ename,sal from emp order by sal asc; 
手动指定按照薪水由小到大排序(升序关键字 asc)
PS:此处desc是descend的缩写, 用法:select * from 表 order by 字段 desc

6 表的约束语句

定义:约束用于限制加入表的数据的类型。保证数据的合法性、完整性、有效性。 可以在创建表时规定约束(通过 CREATE TABLE 语句),或者在表创建之后也可以(通过 ALTER TABLE 语句)。

比如,加唯一性约束(unique)避免昵称重复,

非空约束(not null),

主键约束(primary key):不能为空也不能重复,简称PK

外键约束(foreign),简称PK

检查约束(check),注意Oracle数据库有检查约束,mysql不支持

6.1 非空约束 not null

只有列级约束,没有表级约束

drop table if exists t_user;
create table t_user(
    id int,
    username varchar(255) not null,
    psd varchar(255),
);
insert into t_user(id,username,psd) values(1,123);
-- 报错,必须一一匹配

6.2 唯一性约束 (unique)

修饰的字段具有唯一性,不能重复,但可以为NULL

6.2.1 给一个字段添加unique属性

drop table if exists t_user;
create table t_user(id int,username varchar(255) unique);
insert into t_user(id,username) values(2,'zhang');
insert into t_user(id,username) values(3,'zhang');
-- 报错:  Duplicate entry 'zhang' for key 'username',
-- duplicate重复 entry进入
insert into t_user(id) values(3);
-- 未报错,查询后多一行数据

6.2.1 给多个字段添加unique属性

情况一:表级约束

drop table if exists t_user;
-- 这种方法对两个字段一起约束。只要两个不完全相同就行
create table t_user(id int,username varchar(255),unique(id,username) );
insert into t_user values(1,'li'),(2,'li'),(1,'zhang');
mysql> select * from t_user;
+------+----------+
| id   | username |
+------+----------+
|    1 | li       |
|    1 | zhang    |
|    2 | li       |
+------+----------+
-- 结果正确

情况二:列级约束

drop table if exists t_user;
-- 这种方法分别对两个字段约束。一个字段都不能重复,每个字段都具有唯一性
create table t_user(id int unique,username varchar(255) unique);
insert into t_user values(5,'li'),(5,'zhang');
-- ERROR 1062 (23000): Duplicate entry '5' for key 'id'

6.3 主键约束 (primary key)

一张表的主键约束只能有一个

6.3.1 列级约束

drop table if exists t_user;
create table t_user(id int primary key,-- 列级约束
                    username varchar(255),email varchar(255));
insert into t_user(id,username,email) values(1,'zs','zs@123.com');
insert into t_user(id,username,email) values(2,'ls','ls@123.com');
insert into t_user(id,username,email) values(3,'ww','ww@123.com');
select * from t_user;
+----+----------+------------+
| id | username | email      |
+----+----------+------------+
|  1 | zs       | zs@123.com |
|  2 | ls       | ls@123.com |
|  3 | ww       | ww@123.com |
+----+----------+------------+
insert into t_user(id,username,email) values(1,'la','la@123.com');
-- ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
-- 除主键之外的字段可以为空
insert into t_user(id,email) values(7,'ee');
+----+----------+------------+
| id | username | email      |
+----+----------+------------+
|  1 | zs       | zs@123.com |
|  2 | ls       | ls@123.com |
|  3 | ww       | ww@123.com |
|  5 | gg       | NULL       |
|  7 | NULL     | ee         |
+----+----------+------------+
-- 主键不能为空
insert into t_user(email) values('xx');
-- ERROR 1364 (HY000): Field 'id' doesn't have a default value
-- 主键不能重复
insert into t_user(id,email) values(7,'ee');
-- ERROR 1062 (23000): Duplicate entry '7' for key 'PRIMA'
-- 由上可知,id为主键,因为添加了主键约束,所以==主键字段不能重复也不能为NULL==

6.3.2主键的作用

表的设计三范式中第一范式就要求任何一张表都应该有主键,其作用:

主键值是这行记录在这张表的唯一标识(类似身份证号码

6.3.3 主键的分类

根据主键字段的数量划分:

​ 单一主键 :(常用)

​ 复合主键:多个字段联合起来添加一个主键(不建议使用,违背三范式)

根据主键性质划分:

​ 自然主键:主键值最好是一个和业务没有关系的自然数(推荐这种方式)

​ 业务主键:主键值和系统的业务挂钩,比如,拿着身份证号做主键(不建议使用)修改不方便

最好不要拿和业务挂钩的字段作为主键,因为以后的业务一旦发生大概,主键值可能也需要随之变化,但主键变化可能会导致键值重复

6.2.3 使用表级约束方式定义主键

drop table if exists t_user;
create table t_user(id int,username varchar(255),primary key(id));
insert into t_user(id,username) values(1,'zs');
insert into t_user(id,username) values(2,'ls');
insert into t_user(id,username) values(3,'ws');
select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zs       |
|  2 | ls       |
|  3 | ws       |
+----+----------+
insert into t_user(id,username) values(3,'oo');
-- ERROR 1062 (23000): Duplicate entry '3' for key 'PRIMARY'

主键约束的列级约束和表级约束的区别和唯一性约束的差不多,不同之处是写在每个字段之后还是写在最后边

复合主键: 不建议使用!!!

​ 主键约束的复合主键就是将多个字段联合起来作为主键,联合起来不能重复也不能为空

6.2.4 主键值不可以为NULL

简单记忆为每个人不能没有身份证号

insert into t_student(sname) values('zz');
-- ERROR 1364 (HY000): Field 'sno' doesn't have a default value

6.4 mysql提供主键值自增 (重要) auto_increment

drop table if exists t_user;
-- 设置主键后加auto_increment,主键实现自增,id字段自动维护一个自增的数字,从1递增
create table t_user(id int primary key auto_increment,username varchar(255));
-- 只传入value的值
insert into t_user(username) values('a');
insert into t_user(username) values('b');
insert into t_user(username) values('v');
insert into t_user(username) values('d');
select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | a        |
|  2 | b        |
|  3 | v        |
|  4 | d        |
+----+----------+

6.5 外键约束 (foreign key)

e,g,设计数据库表,维护学生和班级的信息

外键定义在子表引用父表数据的字段

先创建父表再创建子表,删除数据时先删除子表再删除父表,类似于继承的构造和析构,子表引用父表的数据

先插父再插子

-- 因为之前有这两个表,所以删表需要先删子表再删父表,否则会报错
drop table if exists t_student;
drop table if exists t_class;
-- 先创父再创子
create table t_class( cno int primary key,cname varchar(255) );
create table t_student( sno int,sname varchar(255),classno int,primary key(sno),foreign key(classno) references t_class(cno) ); -- reference:引用
insert into t_class values(101,'xxxxxx');
insert into t_class values(102,'yyyyyy');
insert into t_student values(1,'zs1',101);
insert into t_student values(2,'zs2',101);
insert into t_student values(3,'zs3',101);
insert into t_student values(4,'zs4',102);
insert into t_student values(5,'zs5',102);
insert into t_student values(6,'zs6',102);
select * from t_student;
select * from t_class;

insert into t_student values(7,'tt',103);-- 对应班级不存在,a child row:子记录
-- 报错:ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`school`.`t_student`, CONSTRAINT `t_student_ibfk_1` FOREIGN KEY (`classno`) REFERENCES `t_class` (`cno`))

6.5.1 sql脚本的执行

运行sql脚本文件,连接数据库时直接 source+脚本路径即可,路径不可以加引号

source E:\Ty md\mysql\school.sql
Query OK, 0 rows affected (0.01 sec)

……..很多OK,按语句执行

	+------+-------+---------+
	| sno  | sname | classno |
	+------+-------+---------+
	|    1 | zs1   |     101 |
	|    2 | zs2   |     101 |
	|    3 | zs3   |     101 |
	|    4 | zs4   |     102 |
	|    5 | zs5   |     102 |
	|    6 | zs6   |     102 |
	+------+-------+---------+
6 rows in set (0.00 sec)

	+-----+--------+
	| cno | cname  |
	+-----+--------+
	| 101 | xxxxxx |
	| 102 | yyyyyy |
	+-----+--------+
2 rows in set (0.00 sec)

6.5.2 外键值可以为NULL

insert into t_student(sno,sname) values(15,'pp');
select * from t_student;
+------+-------+---------+
| sno  | sname | classno |
+------+-------+---------+
|    1 | zs1   |     101 |
|    2 | zs2   |     101 |
|    3 | zs3   |     101 |
|    4 | zs4   |     102 |
|    5 | zs5   |     102 |
|    6 | zs6   |     102 |
| NULL | pp    |     101 |
|   15 | pp    |    NULL |
+------+-------+---------+

6.5.3 外键不一定是主键

外键引用的别的表某个字段不一定必须要主键,但该字段必须要有唯一性,有unique约束

7. 存储引擎(了解)

mysql特有,为表的存储方式( ORACLE中有对应的机制,名字就叫“表的存储方式” )

7.1 完整的建表语句

create table emp( id int,name varchar(255) );
-- 查看建表语句:
show create table emp;
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                         |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| emp   | CREATE TABLE `emp` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL
) ENGINE=InnoDB DEFAULT COLLATE=utf8mb4_bin |
-- 可以看出默认存储引擎为InnoDB,默认字符集是utf8mb4_bin
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)

-- 完整的建表语句
create table `emp` ( `id` int(11) DEFAULT NULL,`name` varchar(255)  COLLATE utf8mb4_bin DEFAULT NULL)ENGINE=InnoDB DEFAULT COLLATE=utf8mb4_bin;

7.2 查看不同版本支持的存储引擎

每个存储引擎都有其不同的优缺点,应合理选择

-- 显示本版本mysql 5.7.41 支持的存储引擎方式
show engines \G;
-- 共九个
*************************** 1. row ***************************
      Engine: InnoDB
     Support: DEFAULT
     Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
          XA: YES
  Savepoints: YES
*************************** 2. row ***************************
      Engine: MRG_MYISAM
     Support: YES
     Comment: Collection of identical MyISAM tables
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 3. row ***************************
      Engine: MEMORY
     Support: YES
     Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 4. row ***************************
      Engine: BLACKHOLE
     Support: YES
     Comment: /dev/null storage engine (anything you write to it disappears)
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 5. row ***************************
      Engine: MyISAM
     Support: YES
     Comment: MyISAM storage engine
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 6. row ***************************
      Engine: CSV
     Support: YES
     Comment: CSV storage engine
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 7. row ***************************
      Engine: ARCHIVE
     Support: YES
     Comment: Archive storage engine
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 8. row ***************************
      Engine: PERFORMANCE_SCHEMA
     Support: YES
     Comment: Performance Schema
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 9. row ***************************
      Engine: FEDERATED
     Support: NO
     Comment: Federated MySQL storage engine
Transactions: NULL
          XA: NULL
  Savepoints: NULL

7.3 常见的存储引擎

7.3.1 MyISAM

Transaction事务,MyISAM不支持事务,是mysql最常用的存储引擎,但不是默认的

使用三个文件表示一张表:分别用来存储表结构(.frm)、表数据(.MYD)、表的索引(.MYI)

      Engine: MyISAM
     Support: YES
     Comment: MyISAM storage engine
  Transactions: NO
          XA: NO
  Savepoints: NO

 Transaction事务,MyISAM不支持事务,是mysql最常用的存储引擎,但不是默认的
使用三个文件表示一张表:分别用来存储表结构(.frm)、表数据(.MYD)、表的索引(.MYI)
优点:可被压缩,可以转换为只读表,提高检索效率
缺点:不支持事务

7.3.2 InnoDB

      Engine: InnoDB
     Support: DEFAULT
     Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
          XA: YES
  Savepoints: YES
  
  优点:支持事务、行级锁、外键等。这种存储引擎使数据的安全得到保障。
  表的结构存储在.frm文件中
  数据存储在tablespace这样的表空间中(逻辑概念),无法被压缩和转换成只读
  数据库崩溃之后提供自动恢复机制
  支持即联删除和级联更新

7.3.3 MEMORY

	 Engine: MEMORY
     Support: YES
     Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
          XA: NO
  Savepoints: NO
  
缺点:不支持事务。所有数据和索引存储在内存中,容易丢失
优点:查询索引速度最快
以前叫做HEPA引擎

8 事务 (Transaction) -- 很重要

8.1 事务的概述

一个事务是一个完整的业务逻辑单元,不可再分

比如,银行账户转账,从a账户转账10000到b账户,需要执行两次upadate语句

update emp set balance = balance - 10000 where name = 'a';
update emp set balance = balance + 10000 where name = 'b';
-- 以上两条语句必须同时成功或同时失败,不然金额错误
-- 因此需要使用数据库的事务机制

8.2 和事务相关的语句:DML

insert delete update

因为事务的存在是为了保障数据的完整性和安全性,而DML语句是操作表中的数据的

8.3 事务的原理

执行顺序写入缓存,留下操作历史记录,在提交或事务回滚后被清除

事务提交(commit):对应文件随之改变

事务回滚(rollback):将该事务已经完成对数据库的更新操作撤销

两个标志一出来都表示事务结束了

8.4 事务的四大特性(ACID)

1.原子性(atomicity)

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

2.一致性(consistency)

要么同时成功,要么同时失败

数据库总是从一个一致性的状态转换到另一个一致性的状态(在前面的例子中,在没有执行取款前,余额总数为5000,在执行完事务后,取出来的钱再加上银行余额的总数跟原来的余额保持一致性原则,否则要么事务中的语句没有执行完,要么执行过程中出现异常)

3.隔离性(isolation)

事务A与事务B之间有距离

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

4.持久性(durability)

数据必须持久化到硬盘文件里,事务才算成功地结束

一旦事务提交,则其所做的修改会永久保存到数据库(此时即使系统崩溃,修改的数据也不会丢失。)

8.5 事务的隔离性

事务隔离性存在隔离级别,理论上隔离级别有4个:

​ 第一级别:读未提交(read uncommitted)

​ 对方事务还没有提交,我们当前事务可以读取到对方未提交的数据。

​ 读未提交存在脏读(Dirty commited)现象:表示读到了脏的数据

第二级别:读已提交(read committed)

​ 对方事务提交之后的数据我方可以提取到

​ 这种隔离级别解决了脏读现象

​ 存在的问题:不可重复读,可能每次读到的数据不一样

第三级别:可重复读(read committed)

​ 只要事务没结束,数据一直在,重复读取的数据相同

​ 这种隔离级别解决了不可重复读的问题

​ 存在读取到的数据是幻象的问题,读到的是备份数据

第四级别:序列化读/串行化读

​ 解决了所有问题

​ 效率低,事务需要进行排队

Oracle数据库默认的隔离级别是:读已提交

Mysql数据库默认的隔离级别是:可重复读

8.6 演示事务

mysql事务默认情况下自动提交(自动提交:只要执行任意一条DML语句则提交一次)

关闭自动提交:start transaction

演示回滚:

-- 创表
drop table if exists t_user;
create table t_user ( id int primary key auto_increment,username varchar(255) );
-- 演示回滚失败
insert t_user(username) values('zs');
mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zs       |
+----+----------+
mysql> rollback;
mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zs       |
+----+----------+
-- 写一句DML语句后自动提交(committ),回滚后仍是一条记录

-- 演示:使用start transaction;
start transaction;
insert t_user(username) values('ls');
select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zs       |
|  2 | ls       |
+----+----------+
mysql> rollback;
mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zs       |
+----+----------+
-- 回滚成功

演示提交:

start transaction;
insert t_user(username) values('ww');
insert t_user(username) values('jack');
select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zs       |
|  3 | ww       |
|  4 | jack     |
+----+----------+
commit;rollback;
select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zs       |
|  3 | ww       |
|  4 | jack     |
+----+----------+
-- commit提交后数据就写入硬盘了,rollback只能回滚到上一次的提交点

8.7 使用两个事务演示隔离级别

需要开两个cmd窗口表示两个事务

-- 设置事务的隔离级别,global为全局的意思
set global transaction isolation level read uncommitted;
-- 查看事务的全局隔离级别
select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| READ-UNCOMMITTED      |
+-----------------------+
exit;

-- 修改完隔离级别后,所有数据库用户必须退出重新登录,才能使新的隔离级别生效
-- 开两个cmd窗口,都开启事务
-- 1.读未提交:这边写一条数据,还未提交或回滚(即写入硬盘),另一边再查询数据就多出新写的记录
-- 2.读已提交:这边插入数据并提交后,另一边才能查询到记录
-- 3.可重复读:即使这边删除表并提交,那边也可以查询到数据(读的是备份数据)
-- 4.序列化(serializable)/串行化:事务按顺序进行,这边的事务未提交,那边的DML语句一直处于等待状态,一旦这边的事务commit,那边瞬间出结果

9 索引(index)

9.1 定义

索引是给单个字段添加,底层用的B_tree的数据结构

索引相当于目录,在数据库中,查询一张表有两种方式:

​ 第一种:全表扫描

​ 第二种:根据索引检索(缩小扫描范围,提高检索效率)

9.2 添加索引的条件

不能随意添加索引,属于数据库中的对象,数据更改时索引也需要维护,数据经常修改的不适合添加索引;

添加索引:数据量庞大(根据需求和环境)、该字段的DML操作很少、该字段经常出现在where子句中

注意主键和具有unique约束 的字段会自动添加索引

所以,根据主键检索效率较高,尽量使用主句。

9.3 添加 / 删除索引的方式

用explain查看sql语句的执行计划:

explain select username from t_user where username = 'za';
+----+-------------+--------+------------+------+---------------+------+---------+------+------+------
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filt
|  1 | SIMPLE      | t_user | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+------
-- type :ALL表示全表扫描,rows表示扫描的记录数量

给username添加索引

create index 索引名称 on 表名(字段名);

create index t_username_index on t_user(username);
explain select username from t_user where username = 'zs';
 -- type :ref,key变成了索引名,rows=1:只查询了一条记录

给username删除索引

drop index 索引名 on 表名;

drop index t_username_index on t_user;

9.4 索引底层的实现原理

底层索引进行了排序,分区,表的索引会携带着数据在表中的物理地址,作为b+树的叶子节点存储,通过索引检索到数据后,获取到关联的物理地址,通过物理地址定位到表中的数据,效率最高。

9.5 索引的分类

单一索引:给单个字段添加索引

复合索引:给多个字段联合起来添加一个索引

主键索引:主键上自动添加索引

唯一索引:有unique约束的字段上会自动添加索引

9.6 索引的失效

模糊查询时第一个通配符时‘%’,索引无法定位分区,只能使用全局扫描,索引失效

10 视图(了解)

10.1 定义

视图:站在不同的角度看同一张表的数据。(看作另一张表)

创建:create view myview as select empno,ename from emp;

只有select(DQL)语句可以创建视图对象

删除:drop view myview;

create table emp(empno int,ename varchar(255) );

注意:对视图进行CRUD会影响到原表数据

10.2 面向视图操作

mysql> select * from myview;
+-------+-------+
| empno | ename |
+-------+-------+
|     1 | zs    |
|     2 | ls    |
|     3 | ww    |
+-------+-------+

10.3 视图的作用

视图可以隐藏表的实现细节,保密级别较高的系统,数据库只对外提供相关的视图,java程序员只对视图对象进行CRUD

11 DBA命令(了解)

11.1 将数据库中的数据导出

在windows的dos命令窗口中实行(不需要登录数据库):

-- 1.导出整个库
mysqldump 数据库表名>D:\文件名.sql -uroot -proot
-- 将左边的表导入到(>是导入的意思)右边的文件中,要有数据库的密码才行

-- 2.导出指定数据库的指定表
mysqldump 数据库 表名>D:\文件名.sql -uroot -proot

11.2 导入数据

source(之前用过)

12 数据库设计的三大范式

12.1 定义

设计表的依据。按照这个三范式设计的表不会出现数据冗余。

12.2 三范式

第一范式:任何一张表都应该有主键,每个字段的原子性不可再分

第二范式:建立在第一范式的基础上,所有非主键字段完全依赖主键,不能产生部分依赖(不完全依赖)

​ 多对多关系:用三张表,关系表里有两个外键(两张表表示信息,第三张表只用关系表示)

第三范式:建立在第二范式的基础上,所有非主键字段直接依赖主键,不能产生传递依赖

​ 一对多关系:两张表,多的表加外键

提醒:在实际的开发中,以满足客户的需求为主,有的时候会拿冗余数据换执行速度

12.3 一对多的设计

两种方案:主键共享、外键唯一