mysql数据库
1.常见的数据库产品
- 关系型数据库
- MySQL
- MariaDB
- Percona Server
- PostgreSQL
- Oracle
- SQL Server
- Access
- Sybase
- 达梦数据库
- MySQL
- 非关系型数据库
- 面向检索的列式存储 Column-Oriented
- HaBase (Hadoop子系统)
- BigTable (Google)
- 面向高并发的缓存存储key-value
- Redis
- MemcacheDb
- 面向海量数据访问的文档存储 Docuent-Oriented
- MongoDB
- CouchDB
- 面向检索的列式存储 Column-Oriented
2.版本了解
- mysql目前版本8.x。在企业项目中主流版本:5.0…5.5…5.6…5.7。到目前的8.0.x
- 5.x —>2020年5x还在更新
- 8.x —>2018年开始出现。
- mysql8.x特性
- 性能。8.x比5.0快两倍
- 支持nosql存储:5.7开始对nosql的支持。8.x做了更进一步的改进
- 窗口函数
- 索引:隐藏索引、降序索引
- 可用性、可靠性
3.安装mysql
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-89Dyr7QR-1670162631725)(C:\Users\laotianwy\Desktop\SQL\imgs\image-20221123000453211.png)]
4.mysql卸载
-
关闭服务
- net stop mysql80
-
卸载软件
- 控制面板 ->程序功能->卸载mysql server 8.0
-
删除目录
- mysql的安装目录 -> c:\program files (x86)\mysql
-
删除注册表
- win + r —> regedit -> HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\mysql
5.使用mysql命令行
打开 -> MySQL 8.0 Command Line Client ->输入设置的mysql密码
6.SQL分类
- DDL:Data Definition Language 数据定义语言
- 用于完成对数据库对象(数据库、数据表、视图、索引)的创建、
- DML:Data Manipulation Language 数据操作语言
- 添加、删除、修改
- DQL:Data Query Language 数据查看语言
- 将数据查询出来
- DCL:Data Control Language 数据控制语言
- 用于完成事务管理等控制性操作
7.SQL指令
- SQL指令不区分大小写
- 每行语句以分号结尾
;
- SQL关键字以
空格
进行隔开 - SQL之间可以不限制换行,一条语句可以隔行分开写
8.DDL语言、关于数据库的操作
-
查看所有数据库
show databases; # 查看正在使用的数据库 select database();
-
查询一个数据库创建时的语句、可以看到该数据库的字符集
show create database [database_name];
-
创建数据库
create database [database_name];
-
如果数据库不存在再创建
create database if not exists [database_name];
-
创建数据库设置字符集(设置为utf8的字符集、gbk和utf8支持中文)
create database [database_name] character set utf8;
-
修改数据库、(主要是修改数据库的字符集,修改字符集为gbk)
alter database [database_name] character set gbk;
-
字符集有(gbk、utf8、latin1)
-
删除数据库
-
删除数据库会删除数据库中所有的表、及表中的数据
### 删除数据库 drop database [database_name]; ### 如果数据库存在再删除 drop database if exists [database_name];
-
-
使用数据库
### 创建数据库 create database if not exists [database_name] character set gbk; ### 使用某个数据库 use [database_name];
9.DDL表操作(数据定义语言)
-
创建一个表
### varchar、char区别:一个是可变的长度、一个是不可变的长度 ### 中文一个汉字等于两个字符 create table students( stu_id char(8) not null unique, stu_name varchar(20) not null, stu_gender char(2) not null, stu_age int not null, stu_tell char(11) not null unique, stu_qq varchar(11) unique );
-
查看所有的表
### 查看所有的表 show tables; ### 查询某个表的结构 desc [table_name]; ### 删除一个表 drop table [table_name]; ### 如果表存在再删除 drop table if exists [table_name]; ### 修改表的名字 alter table [table_name] rename [change_name]; ### 修改表的字符集、一个表也可以有属于它的字符集 alter table [table_name] character set utf8; ### 修改表添加字段 alter table [table_name] add [column_attr] varchar(200); ### 修改字段的名字和类型。使用change修改表名 alter table [table_name] change [old_column_name] [new_column_name] text; ### 只修改字段的类型、使用modify修改表属性 alter table [table_name] modify [column_name] varchar(200); alter table books modify [column_name] char(4) primary key; ### 删除表的字段 alter table [table_name] drop [column_name]; ### 删除表的主键 alter table [table_name] drop primary key;
-
mysql的数据类型(MySQL中的数据类型大致分为3类)
-
数值类型(一般来讲默认使用int,不够使用了使用bigint)(金钱使用decimal的类型)
类型 内存空间大小(byte) 范围 说明 tinyint 1 -128~127
无符号0~255特小型整数(年龄) smallint 2 -32768~32767
无符号0~65535小型整数 mediumint 3 -8388 608~8388607
无符号0~16777215中型整数 int/integer
4 -2147483648~2147483647
无符号0~4294967295整数 bigint 8 (-9,223,372,036,854,775,808,9 223 372 036 854 775 807)
无符号(0,18 446 744 073 709 551 615)大型整数 float 4 单精度 double 8 双精度 decimal 第一个参数+2 小数值
第一个参数表示一个有多少位、第二个参数是小数的个数是多少个
decimal(10,2):整数有8位、小数有2位 -
字符类型
类型 字符序列的长度范围 说明 char
0-255字节 定长字符串、最多可以存储255个字符。char(n):n的范围就是0-255
此列中的数据最长为n个字符,如果添加的数据少于n,则自动补\u000
到n的长度varchar
0-65535字节 可变长度字符串、此类型的最大长度为65535 tinyblob 0-255字节 存储二进制字符串 blob 0-65535字节 存储二进制字符串 mediumblob 0-1677215 存储二进制字符串 longblob 0-4294967295 存储二进制字符串 tinytext 0-255 文本数据(字符串) text 0-65535 文本数据(字符串) mediumtext 0-1677215 文本数据(字符串) longtext
0-4294967295 文本数据(字符串) -
日期类型
在MySQL中,我们可以使用字符串来存储时间,但是如果我们要基于时间字段进行查询操作,使用字符串就无法进行查询
类型 格式 说明 date 2022-11-24 日期、只能存储年月日 time 22:45:50 时间、只能存储时分秒 year 2022 年份 datetime 2022-11-24 22:45:55 日期+时间:存储年月日时分秒 timestamp 1669301236 时间戳
-
-
字段约束
在创建数据表的时候、指定对数据表列的数据限制性的要求(对列的数据进行限制) 为什么要给表中列的数据添加约束? 保证数据的有效性 保证数据的完整性 保证数据的正确性 ### 非空约束 (限制此列的值必须提供、不能为null) not null ### 唯一约束 (在表中的多条数据、此列的值必须唯一,不能重复) unique ### 主键约束 (非空+唯一。能够唯一标识数据表中的一条数据) primary key ### 外键约束(建立不同表之间的关联关系) foreign key
-
主键
在一张表中、只能有一个主键(主键可以是一个列。也可以是多个列的组合 -> 联合主键) 当一个字段声明为primary key时,此字段数据不能为null,此字段数据不能重复 ### 方式1 create table books( book_isbn char(4) PRIMARY KEY, book_name varchar(10) not null, book_author varchar(8) ); ### 方式2 create table books( book_isbn char(4), book_name varchar(10) not null, book_author varchar(8), primary key(book_isbn) ); ### 主键的自动增长(自动增长从1开始,当删除一条记录时,再新增自动增长不会是上一条的数据,不保证连续) auto_increment 当数据表没有合适的列作为主键时,我们可以额外定义一个与记录本身无关的列作为主键,此列数据无具体的含义,主要用来标志一条数据,在MySQL中我们可以将此列定义为int,同时设置为`自动增长`,当我们向数据表新增数据时,无需提供主键的值,他会自动生成 ### 方式1: create table auto_create( id int primary key auto_increment, name varchar(20) not null, remark varchar(100) );
-
联合主键
将数据表中的多列设置为主键 create table grade( stu_num char(8), course_id int, score double, primary key(stu_num,course_id) );
-
外键
外键约束 在多表关联部门讲解
10.DML(数据操作语言)
- 插入操作
DML:用于完成对表中数据的操作。插入、删除、修改操作
### 方式1:插入数据,字符串用''表示,不允许为空的字段必须提供数据 (推荐这种方式)
insert into [table_name]([many_column]) values([values]);
insert into stus(stu_id,stu_name,stu_gender,stu_age,stu_tell,stu_qq)
-> values('10000','xiaotian','男',23,'17530937281','1695657342');
###方式2:数据列表与创建表的字段保持一致,不可以缺少字段
insert into [table_name] values([数据列表])
insert into stus values('10002','张三','男',100,'12345678911','123456');
-
删除操作
## 从数据表中删除满足条件的数据 delete from [table_name] where [条件] ## 删除指定的信息 delete from stus where stu_id='10000'; ## 删除范围的数据,比如年龄大于20(有多条则删除多条) delete from stus where stu_age>20; ## 删除该表的所有数据 delete from [table_name];
-
修改操作
## 对已经添加的数据进行修改,如果where不写,那么将修改整张表的所有数据 update [table_name] set [arrt=值] where [条件]; update stus set stu_name='xiaotian' where stu_id='10002'; ## 修改多列,多个字段用逗号隔开 update stus set stu_gender='女',stu_age=23 where stu_id='10002';
11.DQL(数据查询语言)
## 查询语句
select [column] from [table_name];
## 查询所有列
slect * from [table_name];
## 查询指定的条件
select * from stus where stu_id = '10002';
## 不等于
select * from stus where stu_id != '10002';
## 不等于
select * from stus where stu_id <> '10002';
##大于
select * from stus where stu_age > 10;
## 小于
select * from stus where stu_age < 10;
## 多条件查询 and 多个条件必须同时满足
select * from stus where stu_age > 10 and stu_qq = '123456';
## or:满足一个条件就可以
select * from stus where stu_age >= 10 or stu_qq = '123456';
## 区间查询 包含a和b
select * from stus where stu_age >= 11 and stu_age <= 24;
select * from stus where stu_age between 11 and 24;
## not:取反。查询除了11到23之间的值
select * from stus where stu_age not between 11 and 23;
操作符 | 说明 | 实例 |
---|---|---|
= | 等于,筛选字段值的精选匹配 | where column_name=value |
!= ,<> | 不等于, | where column_name != value || where column_name <> value |
> | 大于 | |
< | 小于 | |
>= | 大于等于 | |
<= | 小于等于 |
-
模糊查询
在where子句的条件中,可以使用like关键字实现模糊查询 语法: select * from stus where stu_name like '%n%';
操作符 说明 实例 语句说明 % 任意多个字符 select * from stus where stu_name like ‘%n%’; 只要包含字符n就可以了 _ 任意一个字符 select * from stus where stu_name like ‘_i%’; 前面1个,第二个是i,后面任意个 -
计算列
对数据表中查询的记录的列进行一定的运算之后显示出来 select stu_name,2022-stu_age from stus; +-----------+--------------+ | stu_name | 2022-stu_age | +-----------+--------------+ | xiaotian | 1999 | | xiaotian2 | 2012 | | lilei | 1922 | +-----------+--------------+ ### as 字段别名 select stu_name,2022-stu_age as stu_birthday from stus; +-----------+--------------+ | stu_name | stu_birthday | +-----------+--------------+ | xiaotian | 1999 | | xiaotian2 | 2012 | | lilei | 1922 | +-----------+--------------+ ### 中文别名 select stu_name as 姓名,2022-stu_age as 出生年份 from stus; +-----------+----------+ | 姓名 | 出生年份 | +-----------+----------+ | xiaotian | 1999 | | xiaotian2 | 2012 | | lilei | 1922 | +-----------+----------+
-
消除重复的记录 distinct
select distinct [column_name] from [table_name];
-
排序 order by
将查询到的结果按照指定的列进行升序/降序操作。默认是升序 ### 默认是升序 select * from stus where stu_age > 10 order by stu_gender; ### asc升序 select * from stus where stu_age > 10 order by stu_gender asc; ### desc降序 select * from stus where stu_age > 10 order by stu_gender desc; ### 多字段排序,多个字段排序用,号隔开 select * from stus where stu_age > 10 order by stu_gender asc,stu_age desc;,多个字段排序用,号隔开
-
聚合函数
SQL中提供了可以对查询的记录的列进行计算的函数--聚合函数 ### count select count(stu_name) from stus; select count(stu_name) from stus where stu_age > 20; ### max(查询女生年龄最大值) select max(stu_age) from stus where stu_gender='女'; ### min(最小值) select min(stu_age) from stus where stu_gender='女'; ### sum求和 select sum(stu_age) from stus where stu_gender='女'; ### avg求平均值 select avg(stu_age) from stus where stu_gender='女';
-
日期函数与字符串函数
### now(获取当前的时间) update stus set stu_enter_time=now() where stu_name='zhangsan'; ### 通过字符串给日期类型赋值 insert into stus(stu_id,stu_name,stu_gender,stu_age,stu_tell,stu_qq,stu_enter_time) values('10006','zhangsan','男',18,'13253322602','1171004766','2022-11-26 17:28:30'); ### sysdate获取当前系统时间 insert into stus(stu_id,stu_name,stu_gender,stu_age,stu_tell,stu_enter_time) values('10007','lisi','女',22,'11111111111',sysdate()); ### 通过now、sysdate 获取系统时间 select now(); select sysdate(); ### 获取时间 select curtime(); +-----------+ | curtime() | +-----------+ | 17:42:30 | +-----------+ ### 获取日期 select curdate(); +------------+ | curdate() | +------------+ | 2022-11-26 | +------------+ ### 字符串函数 ### concat:对字段进行拼接 select concat(stu_name,'-',stu_gender) from stus; +---------------------------------+ | concat(stu_name,'-',stu_gender) | +---------------------------------+ | xiaotian-女 | | xiaotian2-女 | | lilei-男 | | xiaotian-女 | | zhangsan-男 | | lisi-女 | +---------------------------------+ ### upper:将字符转换为大写 select upper(stu_name) from stus; +-----------------+ | upper(stu_name) | +-----------------+ | XIAOTIAN | | XIAOTIAN2 | | LILEI | | XIAOTIAN | | ZHANGSAN | | LISI | +-----------------+ ### lower:将字符串转换为小写 select lower(stu_name) from stus; ### substring:截取字符串,mysql数据库中索引是从1开始的。第一个参数列名,第二个从第几个开始截取,第三个参数截取几个 select substring(stu_tell,8,4) from stus;
-
分组查询
### group by分组查询。select * 在分组中是没有意义的,一般是分组的列名 select * from stus group by stu_gender; ### 查看该表中性别的分组。过滤重复的数据 select stu_gender from stus group by stu_gender; ### 按照性别进行分组,查询该分组下有多少人 select stu_gender,count(stu_age) from stus group by stu_gender; ### 根据年龄分组。查询该年龄下分别有多少人 select stu_age,count(stu_id) from stus group by stu_age; ### 查询完排序 select stu_age,count(stu_id) from stus group by stu_age order by stu_age asc; ### 分组使用聚合函数,格局性别进行分组,并且根据分组结果计算年龄的和 select stu_gender,sum(stu_age) from stus group by stu_gender; +------------+--------------+ | stu_gender | sum(stu_age) | +------------+--------------+ | 女 | 77 | | 男 | 118 | +------------+--------------+ ### 分组筛选 ### having:将分组后的结果进行查询筛选(having必须和分组使用) select stu_age,count(stu_id) from stus group by stu_age having count(stu_id) > 1 order by stu_age desc; select stu_age,count(stu_id) as 当前年龄的个数 from stus group by stu_age having count(stu_id) > 1 order by stu_age asc; ### 以男生查询并以年龄分组,如果分组后的年龄 》 10才显示,根据升序排序 select stu_age,count(stu_id) from stus where stu_gender='男' group by stu_age having max(stu_age > 10) order by stu_age;
-
分页查询
### limit 分页查询(第一个参数第几条开始,索引为0。第二个参数获取几条数据) 语法:select ... from ... where ... limit params1,params2 select * from stus limit 0,3;
12.表的关联关系
mysql是一个关系型数据库,不仅可以存储数据。还可以维护数据与数据之间的关系,通过数据表中添加字段建立外键约束
数据与数据之间的关联关系分为四种
1.一对一关联
2.一对多关联
3.多对一关联
4.多对多关联
-
一对一关联
人 <-> 身份证 一个人只有一个身份证,一个身份证只对应一个人 学生 <-> 学籍 一个学生只有一个学籍,一个学籍只对应唯一的一个人 用户 <-> 用户详情 一个用户只有一个详情,一个详情也只对应一个用户 一对一关联如何实现: 方式1:主键关联,两张数据表中主键相同的数据为相互对应的数据 方式2:唯一的外键,在任意一张表中添加一个字段为外键,与并一张表主键关联,并且该外键设置为唯一
-
一对多或者多对一关联
班级 <->学生 一对多,一个班级包含多个学生 学生 <->班级 多对一,多个学生对应一个班级 一对多如何实现: 在多的一端添加外键,与一的一端主键相互关联
-
多对多
学生 <-> 课程 一个学生可以选择多门课程,一门课程可以被多个人选择 会员 <-> 社团 一个会员可以选择多个社团,一个社团可以招纳多个会员 多对多如何实现: 额外创建一张关系表来维护多对多关联。在关系表中定义两个外键,分别与两个数据表中的主键关联
-
外键约束
# 外键约束,将一个列添加外键约束与另一张表的主键(唯一列)进行关联,这个外键约束的列的数据必须在关联的表的主键(唯一)列中存在 # 重点:由于学生列要与班级表的class_id关联,因为cid字段类型和长度要与class_id一致! # 案例:学生表与班级表 create table classes( class_id int primary key auto_increment, class_name varchar(40) not null unique, class_remark varchar(200) ); # 学生表创建。constraint:限制。foreign key:外键。references:参考 # constraint [name] foreign key[current_table_column] references [table_name]([column_name]) # 方式1:在创建表的时候添加字段为外键 create table students( stu_num char(8) primary key, stu_name varchar(20) not null, stu_gender char(2) not null, stu_age int not null, cid int, constraint FK_STUDENTS_CLASSES foreign key(cid) references classes(class_id) ); # 方式2:添加的时候不设置为外键,修改表的属性为外键 create table students( stu_num char(8) primary key, stu_name varchar(20) not null, stu_gender char(2) not null, stu_age int not null, cid int ); alter table students add constraint FK_STUDENTS_CLASSES foreign key(cid) references classes(class_id); # 删除表的外键约束 alter table students drop foreign key FK_STUDENTS_CLASSES;
-
如何更新外键约束
#方式1:先把外键设置为null,修改外键的主键表,再把外键的表的字段重新设置 update students set cid=null where cid=4; update from classes set class_id=5 where class_id=4; update students set cid=5 where cid is null; #方式2: 把外键添加为级联操作。第一步先删除外键,第二步把字段设置为外键并且设置级联 alter table students drop foreign key FK_STUDENTS_CLASSES; alter table students add constraint FK_STUDENTS_CLASSES foreign key(cid) references classes(class_id) ON UPDATE CASCADE ON DELETE CASCADE; # 重点:级联操作如果更改外键的值,那么外键会一起更改 # 如果外键的主键数据被删除了,那么此外键的一行数据也会被删除
13.多表查询
1.多表查询有三种
1.内链接 inner join
2.左连接 left join
3.右链接 right join
-
内链接
# 语法 select ... from table_name1 inner join table_name2; #内连接查询的数据是根据笛卡尔积来显示的 笛卡尔积:使用A中的每个记录关联B的所有记录,1条一次关联多条记录.笛卡尔积的总数是A乘B 内链接会生成许多没有意义的数据 # 筛选有意义的数据. # 方式1:使用where获取的数据效率是很低的,先生成笛卡尔积.然后再进行过滤 SELECT * from students INNER JOIN classes WHERE students.cid = classes.class_id; # 方式2:使用on获取数据的效率是很高的.先判断链接条件是否成立,如果成立再组合两张表的数据.生成一条数据 SELECT * from students INNER JOIN classes ON students.cid = classes.class_id;
-
左连接
左连接:显示左表的所有数据,如果在右表中存在与左表记录满足匹配条件的数据,则进行匹配.如果右表中不存在匹配记录,则显示null 注意:左连接只能使用on.不能使用where 语法:SELECT ... from [left_table] LEFT JOIN [right_table] ON [匹配条件] [where 条件];
-
右链接
右连接:显示右表的所有数据,如果在左表中存在与右表记录满足匹配条件的数据,则进行匹配.如果左表中不存在匹配记录,则显示null 注意:右连接只能使用on.不能使用where 语法:SELECT ... from [left_table] RIGHT JOIN [right_table] ON [匹配条件] [where 条件];
-
表添加别名(在表的后面添加空格 添加名字)
SELECT s.*,c.class_name from students s LEFT JOIN classes c on s.cid = c.class_id;
-
子查询
# 查询java202211班的所有人 select * from students where cid = (select class_id from classes where class_name = 'java202211'); # 使用union,将查询的多条记录拼接在一起 # 查询java班的人 select * from classes where class_name like 'Java%'; select * from students where cid = 1 union select * from students where cid = 4; # 如果查询的条件是单列多行,那么使用in进行查询 select * from students where cid in (select class_id from classes where class_name like 'Java%'); # not in 查询不在多条记录里的数据 select * from students where cid not in (select class_id from classes where class_name like 'Java%'); # 方式1:查询cid = 1并且性别是男的学生 select * from students where cid = 1 and stu_gender = '男'; # 方式1:查询cid = 1并且性别是男的学生,临时表需要添加别名 select * from (select * from students where cid = 1) template where template.stu_gender = '男';
14.mysql高级
-
mysql指令执行过程
从sql执行的过程中,分析到存在的问题: 1.如果我们需要重复多次执行相同的sql,sql执行都需要通过连接传递到mysql,并且需要经过编译和执行的步骤 2.如果我们需要执行多个sql指令,并且第二个sql指令需要使用第一个sql指令执行的结果作为参数,那么是不可能的
-
存储过程
存储过程:将能够完成特定功能的sql指令进行封装(sql指令集),编译之后存储在数据库服务器上,并且为这个指令取一个名字,客户端可以通过名字直接调用这个sql指令集,获取执行结果.不需要重复编译sql指令 存储过程优点: 1.sql指令无需客户端编写,通过网络传递名字,可以节省网络开销,同时避免sql指令在网络传输过程中被恶意更改.保证安全性 2.存储过程经过编译创建并保存在数据库中,执行过程无需重复的进行编译操作,对sql指令的执行过程进行了性能提升 3.存储过程多个sql指令之间存在逻辑关系,支持流程控制语句(分支.循环),可以实现复杂的业务 存储过程缺点: 1.存储过程是根据不同的数据库进行编译,创建.并存储在数据库中,当我们需要切换到其他的数据库时,需要重新编写新的存储过程.比如MySQL切换到Oracle 2.存储过程受限于数据库产品,如果需要高性能的优化会成为一个问题 3.在互联网项目中,如果需要数据库的高并发访问,使用存储过程会增加数据库的连接执行时间(因为我们将复杂的业务交给了数据库进行处理)
-
存储过程语法
# 语法 create procedure [procedure_name]([in/out args]) begin end; create procedure proce_test6(in a int,in b int,out c int) begin set c = a - b; end;
-
调用存储过程
--定义变量 set @m = 0; -- 调用存储过程, call proce_test6(3,2,@m); -- 显示变量的值 select @m from dual;
-
存储过程中变量的使用
存储过程的变量分为2种:局部变量和用户变量 局部变量:定义在存储过程中的变量,只能在存储过程内部使用 布局变量定义语法: declare [var_name] [type] default [default_value]; create procedure procedure_test2(in a int,out r int) begin declare x int default 0; declare y int default 1; set x = a * a; set y = a / 2; set r = x + y; end; 用户变量:相当于全局变量,定义的用户变量可以通过 select @attr_name from dual; 进行查询 用户变量会存储在mysql数据库的数据字典中(dual) 用户变量定义使用set来定义,变量名要以@开头. 因为用户变量相当于全局变量,可以在sql指令以及多个存储过程中共享,所以在开发中尽少使用用户变量,过多会导致程序不易理解。难以维护
-
变量设置值
无论是用户变量还是局部变量,都是以set关键字设置值 set @n = 10; call procedure_test2(6,@n) select @n from dual;
-
存储过程,查询给变量赋值
-- 创建存储过程,查询学生的数据并返回 set @num = 0; create procedure search_school_num(out c int) begin select count(stu_name) into c from students; end; call search_school_num(@num); select @num from dual;
15.存储过程的参数
mysql的存储过程的参数有三种:IN\OUT\INOUT
-
IN输入参数
输入参数,在调用存储过程中传递数据给存储过程的参数(在调用的过程中必须为具有实际值的变量 或者 字面值) -- 创建存储过程添加学生信息 create procedure add_student(In snum char(8),IN stu_name varchar(20),In stu_gender char(2),IN stu_age int,IN cid int,In remark varchar(255)) begin INSERT INTO students(stu_num,stu_name,stu_gender,stu_age,cid,remark) VALUES(snum,stu_name,stu_gender,stu_age,cid,remark); end; call add_student('3','xiaoyan','女',22,2,'这是备注');
-
OUT输出参数
输出参数,将存储过程中产生的数据返回给过程调用者,相当于javascript方法的返回值,但不同的是一个存储过程可以有多个输出参数 -- 根据学号查询学生的姓名 create procedure find_student_name(IN num varchar(8),OUT sname varchar(20)) begin select stu_name into sname from students where stu_num = num; end; set @findName = 'test'; call find_student_name('3',@findName); select @findName from dual;
-
INOUT输入输出参数
-- 根据inout学号查询学生的姓名 create procedure find_student_name2(INOUT sname varchar(20)) begin select stu_name into sname from students where stu_name = sname; end; set @inoutName = 'xiaoyan'; call find_student_name2(@inoutName); select @inoutName from dual;
16.存储过程流程控制
在存储过程中支持流程控制语句用于实现逻辑的控制
-
分支语句
if-then-else # 单分支 -- 分支语句. if-then-else -- 创建一个存储过程,如果输入的参数是1,那么新增一条班级数据 -- 2,删除一条班级数据 create procedure if_func(in type int) begin if type = 1 then insert into classes(class_name) VALUES('前端202211'); end if; end; call if_func(1); # 多分支 create procedure if_else_func(in type int) begin if type = 1 then insert into classes(class_name) VALUES('前端202211'); else delete from classes where class_name = '前端202211'; end if; end; call if_else_func(2); # 使用case进行分支 create procedure case_func(IN flag int) begin case flag when 1 then insert into classes(class_name) VALUES('前端202211');-- SQL when 2 then delete from classes where class_name = '前端202211';-- SQL else update classes set class_name = 'python202211' where class_name = '前端202211';-- SQL end case; end; call case_func(3);
-
循环查询
# 使用while 进行循环添加表数据 create procedure for_func(IN num int) begin declare i int; set i = 0; while i<num do insert into classes(class_name) VALUES(CONCAT('java',i)); set i = i + 1; end while; end; call for_func(5); # reap 循环 create procedure repeat_func(IN num int) begin declare i int; set i = 0; repeat insert into classes(class_name) VALUES(CONCAT('python',i)); set i = i+1; UNTIL i>num end repeat; end; call repeat_func(4); # loop # 使用loop循环执行sql create procedure loop_func(in num int) begin declare i int; set i = 0; myloop:loop insert into classes(class_name) VALUES(CONCAT('大数据',i)); set i = i +1; if i = num then leave myloop; end if; end loop; end; call loop_func(5)
17.存储过程管理
# 查询存储过程 -> 查询某个数据库有哪些存储过程 # 储存过程是属于某个数据库的,也就是说当我们将存储过程创建在某个数据库之后,只能在当前数据库中调用此存储过程 # 根据数据库名查询当前数据库的存储过程 show procedure status where db='db_test2'; # 查询存储过程的创建细节 show create procedure db_test2.add_student; #修改存储过程。指的是修改存储过程的特性\特性 alter procedure [procedure_name] 特征1 特征2 # 修改存储过程 ALTER PROCEDURE add_student READS SQL DATA; # 删除存储过程 -- drop 删除数据库对象,数据库,数据表,列,存储过程,视图,触发器,索引... drop procedure add_student;
-
存储过程的特征
contains SQL:表述子程序包含sql语句,但不包含读或写数据的语句 no sql:表示子程序不包含sql语句 reads sql data:表述子程序中包含读数据的语句 MODIFIES SQL data:表示子程序中包含写数据的语句 sql SECURITY:指明谁有权限来执行 DEFINER:表示只有定义者自己才能执行 INVOKER:表示调用者可以执行 COMMENT 'string':表示注释信息
-
存储过程实现借书
# 查询创建数据库的语句 show create database db_book; # 创建图书信息表 create table books( book_id int primary key auto_increment, book_name varchar(50) not null, book_author varchar(20) not null, book_price decimal(10,2) not null, book_stock int not null, book_desc varchar(200) ); # 添加图书信息 insert into books(book_name,book_author,book_price,book_stock,book_desc) values('java程序设计','小亮',38.80,12,'带你学java'); insert into books(book_name,book_author,book_price,book_stock,book_desc) values('python程序设计','小红',44.20,10,'带你学python'); # 创建学生表 create table students( stu_id int primary key auto_increment, stu_name varchar(20) not null, stu_gender char(2) not null, stu_age int not null ); # 添加学生信息 insert into students(stu_name,stu_gender,stu_age) values('张三','男',20); insert into students(stu_name,stu_gender,stu_age) values('李四','男',30); insert into students(stu_name,stu_gender,stu_age) values('王五','男',40); # 借书记录表 create table records( rid int primary key auto_increment, sid int not null, bid int not null, borrow_num int not null COMMENT '借书的数量', is_return int not null COMMENT '0-未归还 1-已归还', borrow_date date not null comment '归还日期', constraint FK_RECORDS_STUDENTS foreign key(sid) REFERENCES students(stu_id), constraint FK_RECORDS_BOOKS foreign key(bid) references books(book_id) ); # 创建存储过程,实现学生借书 # 借书状态(1-成功 2-学号不存在 3图书不存在 4-库存不足) create procedure proc_borrow_book(In a int,In b int,In borrow_num int,OUT state int) begin declare stu_count int default 0; declare book_count int default 0; declare stock int default 0; -- 判断学号是否存在 select count(stu_id) into stu_count from students where stu_id = a; if stu_count > 0 then -- 学号存在 select count(book_id) into book_count from books where book_id = b; if book_count > 0 then -- 如果图书存在,判断图书库存是否充足 select book_stock into stock from books where book_id = b; if stock > borrow_num then -- 如果库存的数量大于借的数量,执行借书 insert into records(sid,bid,borrow_num,is_return,borrow_date) values(a,b,borrow_num,0,SYSDATE()); -- 修改库存记录 update books set book_stock = stock - borrow_num where book_id = b; set state = 1; else -- 不借,缺货 set state = 4; end if; else -- 如果图书不存在 set state = 3; end if; else -- 学号不存在 set state = 2; end if; end; set @state = 0; call proc_borrow_book(1,1,1,@state); select @state from dual;
18.concal_ws的使用
# concat_ws 的使用
create procedure proc_test1(IN id int,OUT result varchar(100))
begin
declare name varchar(50);
declare author varchar(20);
declare price decimal(10,2);
select book_name,book_author,book_price into name,author,price from books where book_id = id;
set result = CONCAT_WS('-',name,author,price);
end;
set @r = '';
call proc_test1(1,@r);
select @r from dual;
19.游标
创建一个存储过程,如果需要返回一个语句的多条查询结果,该怎么操作。那么就使用游标来进行实现
游标可以依次取出每一条数据
# 使用游标
# 使用游标,指向当前的每一条记录,(提取之后,游标自动下移)
create procedure proc_test2(OUT result varchar(200))
begin
declare bname varchar(50);
declare author varchar(20);
declare price decimal(10,2);
declare book_num int;
declare i int default 0;
declare str varchar(50) default '';
declare mycursor cursor for select book_name,book_author,book_price from books;
select count(1) into book_num from books;
open mycursor;
while i < book_num do
fetch mycursor into bname,author,price;
set i = i + 1;
select CONCAT_WS('-',bname,author,price) into str;
set result = CONCAT_WS(',',result,str);
end while;
close mycursor;
end;
set @result_string = '';
call proc_test2(@result_string);
select @result_string from dual;
20.触发器
触发器,就是一种特殊的存储过程,触发器和存储过程一样是一个完成特定功能,存储在数据库服务器上的sql片段,但是触发器无需调用,当对数据表中的数据进行DML操作时自动触发这个sql片段,无需手动调用
执行insert\delete\update时自动触发
语法
create trigger [tri_name]
[before/after] -- 定义触发时机
[insert/update/delete] -- 触发行为
on [table_name]
for each row -- 声明为行级触发器,(只要操作一条记录那么就执行一次)
begin
end;
实例:
# 触发器
create table `logs`(
id int primary key auto_increment,
time timestamp,
log_text varchar(200)
);
create trigger tri_test1
after insert on students
for each row
insert into logs(time,log_text) values(now(),concat('添加',new.stu_id,'学生信息'));
insert into students(stu_name,stu_gender,stu_age) values('小田','男',23);
# 查看触发器
show TRIGGERS;
# 删除触发器
drop trigger tri_test1;
21.触发器的new与old
触发器用于监听数据表的操作。我们可以使用new,old关键字获取触发的数据
- new:在触发器中用于获取insert操作添加的数据,update操作修改后的数据
- old:delete操作前的数据,update前的数据
# 触发器的修改
create trigger tri_test1
after update on students
for each row
insert into logs(time,log_text) values(now(),concat(old.stu_name,'学生信息修改',new.stu_name));
update students set stu_name = '小红' where stu_name = '小田';
# 触发器的删除
create trigger tri_test1
after delete on students
for each row
insert into logs(time,log_text) values(now(),concat('将学生姓名为:',old.stu_name,'删除'));
delete from students where stu_name = '小红';
22.触发器使用总结
优点:
触发器是自动执行的,当对触发器相关的表执行DML时,自动执行
触发器可以实现表中数据的级联操作(关联操作),有利于保证数据的完整性
触发器可以对DML操作的数据进行更为复杂的合法性校验
缺点:
使用触发器实现的业务逻辑如果出现问题将难以复位,后期维护困难
大量使用触发器容易导致代码结构杂乱,增加了程序的复杂性
当触发器操作的数据量比较大时,执行效率会降低
建议:
在互联网项目中应该避免使用触发器
对于并发量不大的项目可以选择使用存储过程,但是在互联网实战中不建议使用存储过程(存储过程时将业务交给了数据库进行处理,增加了数据库的负载。不利于数据库的迁移)
23.视图
视图的概念:
视图,就是由数据库中一张表或者多张表根据特定的条件查询出的数据构成的 虚拟表
视图的作用:
安全性:如果我们直接将数据表授权给用户操作,那么用户可以crud数据表中的所有数据,假如我们需要对数据表的字段进行保护,那么将公开的字段生成视图,授权用户访问视图,用户通过查询视图可以获取数据表中公开的数据,从而达到对部分数据的保护
简单性:如果我们需要查询的数据来源与多张数据表,可以使用多表连接查询来实现,我们通过视图将这些联表查询的结果对外开放,用户则可以直接查询视图获取多表查询的结果,操作更便捷
创建视图语法:
create view [view_name] AS select_statement;
创建视图1:
create view view_test1 as select * from students;
select * from view_test1;
创建视图2:
create view view_test2 as select s.stu_name,b.book_name,borrow_num from books b INNER JOIN records r INNER JOIN students s on b.book_id = r.bid and r.sid = s.stu_id;
select * from view_test2;
24.视图数据的特性
视图是虚拟表。查询视图的数据来源于数据表。当对视图进行操作时,对原数据表的数据是否由影响?
当视图是一张表时,对视图数据的增删改差。都会影响到原表
当视图是多表联查,不可更改、删除、插入视图数据
视图的使用建议:对复杂查询的简化操作,并且不会对数据进行修改的情况下可以使用视图
25.视图操作
# 查询视图结构
desc [view_name];
# 查询创建视图的语句
show create view [view_name];
# 修改视图
create or replace view [view_name] as select * from students where stu_gender = '男';
# 修改视图方式2:
alter view [view_name] as select * from students where stu_gender = '女';
# 删除视图 (删除视图只会删除视图的名字,并不会删除原表的数据)
drop view [view_name];
26.索引
数据库用来存储数据的,在互联网项目数据库中存储的数据可能很大,数据表中的数据的查询速度会随着数据量大而逐渐变慢,从而影响用户请求的速度,如何提升查询的速度?
索引就是用来提高数据表的查询效率的。
索引:就是将数据的某一列/某几列的值取出来构造成便于查找的结构进行存储,生成数据表的目录,当我们进行数据查询的时候。则现在目录中进行查找得到对应的数据的地址,然后再到数据表中根据地址快速获取数据记录,避免全表扫描。
索引的分类:
MySQL中的索引,根据创建的索引的列不同,可以分为:
主键索引:在数据表中的主键字段创建的索引,这个字段必须被primary key修饰,每个表只能有一个主键
唯一索引:在数据表中的唯一列创建的索引,unique,此列的所有值只能出现一次,可以为null
普通索引:普通字段创建的索引,没有唯一性的限制
组合索引:两个及以上的字段联合起来创建的索引
创建索引:
# 唯一索引
create unique index [index_name] on [table_name](column_name);
create unique index test_index on logs(`time`);
# 普通索引
create index [index_name] on [table_name](column_name);
create index test_index on logs(`time`);
# 组合索引
create index [index_name] on [table_name](column_name1,column_name2);
create index group_index on logs(time,log_text);
# 全文索引
在mysql5.6版本新增的索引,可以通过此索引进行全文检索操作,因为mysql全文索引不支持中文,因此这个索引不被开发者关注,在应用开发中通常通过搜索引擎(数据库中间件)实现全文索引。es
create fulltext index [index_name] on [table_name](column_name);
27.索引的使用
索引创建完成之后无需调用,当根据创建索引的列进行数据查询的时候,会自动使用索引。
组合索引需要根据组合索引的所有字段进行查询才能触发
# 在命令行查询当前语句是如何查询的
explain select * from [table_name] where [column_name] = [value]\G;
explain select * from logs where id = 6\G;
# 查看当前表的索引 命令行
show create table logs\G
# 使用可视化查询
show indexes from [table_name];
show keys from [table_name];
# 删除表的索引
drop index [index_name] on [table_name];
drop index test_index on logs;
28.索引总结
优点:
索引大大降低了数据库服务器在执行查询操作时扫描的数据,提高查询效率
索引可以避免服务器排序,将随机io变成顺序io
缺点:
索引是根据数据表列创建的,当数据表中的数据发生DML操作时,索引也需要更新
索引文件会占用磁盘空间
注意事项:
数据表中数据不多时,全表扫描可能更快,不需要使用索引
数据量大但是DML操作很频繁,不建议使用索引
不要在数据重复率高的列上创建索引,比如性别
创建索引之后,要注意查询SQL语句的编写。避免索引失效
29.事务
我们把完成特定业务的多个数据库DML操作步骤称之为一个事务
事务,就是完成一个业务的多个DML操作。比如借书。银行转账。
数据库事务的特性、ACID特性:
原子性(Atomicity):一个事务的多个DML操作,要么同时成功。要么同时失败
一致性(Consistency):事务执行之前和事务执行之后,数据库中的数据是一致的,完成性和一致性不能被破坏。执行前的数量和执行后的数量一致
隔离性(lsolation):数据库允许多个事务同时执行,多个并行的事务之间不能被影响(张三可以借书、李四也可以借书)
持久性(Durability):事务完成之后对数据库的操作是永久的
30.事务管理
自动提交与手动提交
在MySQL中,默认DML指令的执行是自动提交的,当我们执行一个DML指令之后,自动同步到数据库表中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WbZw1ibP-1670162631726)(C:\Users\laotianwy\Desktop\SQL\imgs\image-20221202234118495.png)]
开启事务。就是关闭自动提交
在开启事务第一个操作之前执行start transaction 命令
依次执行事务中的每个DML操作
如果在执行的过程中任何位置出现异常,则执行回滚操作rollback
如果事务中所有的DML操作都执行成功,则在最后执行commit操作提交事务
31.事务管理级别
数据库允许多个事务并行,多个事务之间是隔离的,相互独立的。如果事务之间不相互隔离并且操作同一数据,可能会导致数据的一致性被破坏
读未提交(read uncommitted):事务2读取事务1执行但是未提交的数据;可能会出现脏读。脏数据
读已提交(read commited):事务2读取事务1已经提交的数据,可能会导致不可重复读(虚度)。第二次读和第一次读不一样
可重复读(repeatable read):事务2执行第一次查询之后,在事务结束之前其他事务不能修改对应的数据。避免了不可重复读(虚读),但是可能导致幻读。(事务2修改并读取了表的数据。在查询之前事务1提交了一条数据,导致事务2以为修改了数据,但是查询出了与修改不一致的数据。多了一个事务1新增的数据)
串行化(serializable):同时只允许一个事务对数据表进行操作,避免了脏读、虚读、幻读问题.
32.设置数据库事务隔离级别
我们可以通过设置数据库默认隔离级别来控制事务之间的隔离性
也可以通过客户端与数据库连接设置事务间的隔离性(比如spring)
mysql默认的隔离级别是可重复读
# MySQL中查看隔离级别。
# 在8.0.3之前
select @@tx_isolation;
# 在8.0.3之后
select @@TRANSACTION_isolation;
# 设置MySQL默认的隔离级别
set session transaction isolation level [isolation_name];
set session transaction isolation level REPEATABLE READ;
33.数据库设计
MySQL数据库作为数据存储的介质为应用系统提供数据存储的服务,我们如何设计合理的数据库、数据表以满足应用系统的数据存储需求呢?
- 车库:是用来存放车辆的,车库需要划分车位,如果不划分车位,车子杂乱无章的存放可能会导致车辆阻塞,同时也可能导致场地的浪费–有限的场地能够存放最多的车辆,同时方便每一辆车的进入
- 数据库是用来存放数据的,我们需要设计合理的数据表。能够完成数据的存储,同时能够方便的提取应用系统所需的数据
34.数据库设计流程
数据库是为应用系统所服务的,数据库存储什么样的数据也是由应用系统来决定的。
当我们进行应用系统开发时,我们首先要明确应用系统的功能需求。软件系统的需求分析
1.根据应用系统的功能,分析数据实体(实体,就是要存储的数据对象)
电商系统:商品、用户、订单
教务管理系统:学生、课程、成绩、
2.提取实体的数据项(数据项就是实体的属性)
商品(商品名称、图片、描述)
用户(姓名、登录名、登录密码)
3.根据数据库设计三范式规范视图的数据项(检查实体的数据项是否满足数据库设计三范式)
如果实体的数据项不满足三范式、可能会导致数据的冗余、从而引起数据维护困难、破坏数据一致性等问题
4.绘制E-R图(实体关系图,直观的展示实体与实体之间的关系)
5.数据库建模
三线图进行数据库表设计
PowerDesigner
PDMan
6.建数据表(编写SQL指令创造数据库、数据表)
7.添加测试数据、SQL测试
35.数据库表设计三范式
- 第一范式:要求数据表中的字段(列)不可再分
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QcBP2QPS-1670162631727)(C:\Users\laotianwy\Desktop\SQL\imgs\image-20221204203807014.png)]
-
第二范式:不存在非关键字段对关键字段的部分依赖
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7PNwfhg2-1670162631727)(C:\Users\laotianwy\Desktop\SQL\imgs\image-20221204203905853.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-60zkUstw-1670162631728)(C:\Users\laotianwy\Desktop\SQL\imgs\image-20221204204141131.png)]
- 第三范式:不存在非关键字段之间的传递依赖
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SAFQtqCu-1670162631728)(C:\Users\laotianwy\Desktop\SQL\imgs\image-20221204204915605.png)]
-
图书管理系统e-r图与三线图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xh4KFMdM-1670162631729)(C:\Users\laotianwy\Desktop\SQL\imgs\image-20221204215134310.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8vg18C1e-1670162631729)(C:\Users\laotianwy\Desktop\SQL\imgs\image-20221204210344811.png)]
-
powerdesign
为修改了数据,但是查询出了与修改不一致的数据。多了一个事务1新增的数据)
串行化(serializable):同时只允许一个事务对数据表进行操作,避免了脏读、虚读、幻读问题.
## 32.设置数据库事务隔离级别
我们可以通过设置数据库默认隔离级别来控制事务之间的隔离性
也可以通过客户端与数据库连接设置事务间的隔离性(比如spring)
mysql默认的隔离级别是可重复读
MySQL中查看隔离级别。
在8.0.3之前
select @@tx_isolation;
在8.0.3之后
select @@TRANSACTION_isolation;
设置MySQL默认的隔离级别
set session transaction isolation level [isolation_name];
set session transaction isolation level REPEATABLE READ;
## 33.数据库设计
MySQL数据库作为数据存储的介质为应用系统提供数据存储的服务,我们如何设计合理的数据库、数据表以满足应用系统的数据存储需求呢?
- 车库:是用来存放车辆的,车库需要划分车位,如果不划分车位,车子杂乱无章的存放可能会导致车辆阻塞,同时也可能导致场地的浪费--有限的场地能够存放最多的车辆,同时方便每一辆车的进入
- 数据库是用来存放数据的,我们需要设计合理的数据表。能够完成数据的存储,同时能够方便的提取应用系统所需的数据
## 34.数据库设计流程
数据库是为应用系统所服务的,数据库存储什么样的数据也是由应用系统来决定的。
当我们进行应用系统开发时,我们首先要明确应用系统的功能需求。软件系统的需求分析
1.根据应用系统的功能,分析数据实体(实体,就是要存储的数据对象)
电商系统:商品、用户、订单
教务管理系统:学生、课程、成绩、
2.提取实体的数据项(数据项就是实体的属性)
商品(商品名称、图片、描述)
用户(姓名、登录名、登录密码)
3.根据数据库设计三范式规范视图的数据项(检查实体的数据项是否满足数据库设计三范式)
如果实体的数据项不满足三范式、可能会导致数据的冗余、从而引起数据维护困难、破坏数据一致性等问题
4.绘制E-R图(实体关系图,直观的展示实体与实体之间的关系)
5.数据库建模
三线图进行数据库表设计
PowerDesigner
PDMan
6.建数据表(编写SQL指令创造数据库、数据表)
7.添加测试数据、SQL测试
## 35.数据库表设计三范式
- 第一范式:要求数据表中的字段(列)不可再分
[外链图片转存中...(img-QcBP2QPS-1670162631727)]
- 第二范式:不存在非关键字段对关键字段的部分依赖
[外链图片转存中...(img-7PNwfhg2-1670162631727)]
[外链图片转存中...(img-60zkUstw-1670162631728)]
- 第三范式:不存在非关键字段之间的传递依赖
[外链图片转存中...(img-SAFQtqCu-1670162631728)]
- 图书管理系统e-r图与三线图
[外链图片转存中...(img-Xh4KFMdM-1670162631729)]
[外链图片转存中...(img-8vg18C1e-1670162631729)]
- powerdesign
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zqh0taUB-1670162631730)(C:\Users\laotianwy\Desktop\SQL\imgs\image-20221204213839185.png)]