视频课链接1:047-MySQL-关联关系-一对多、多对一_哔哩哔哩_bilibili047-MySQL-关联关系-一对多、多对一是千锋教育MySQL数据库教程,mysql安装到mysql高级一套通关的第49集视频,该合集共计110集,视频收藏或关注UP主,及时了解更多相关视频内容。https://www.bilibili.com/video/BV1qb4y1Y722?p=49&spm_id_from=pageDriver&vd_source=409c279a570617f1f63ce4ae8695f69f
视频课链接2:51. 基础-事务-简介_哔哩哔哩_bilibili51. 基础-事务-简介是黑马程序员 MySQL数据库入门到精通,从mysql安装到mysql高级、mysql优化全囊括的第51集视频,该合集共计195集,视频收藏或关注UP主,及时了解更多相关视频内容。https://www.bilibili.com/video/BV1Kr4y1i7ru?p=51&vd_source=409c279a570617f1f63ce4ae8695f69f
关系型数据库:采用了关系模型来组织数据存储,以表格的形式存储数据并记录数据之间的关系,可以建立表格间的关联来维护数据和数据间的关系。
非关系型数据库:采用键值对的模型来存储数据,不记录数据间的关系。在非关系型数据库中基于特定的存储结构来解决一些大数据应用的难题。常用NoSQL(Not only SQL)数据库来指代非关系型数据库。
关系型数据库:
MySQL,PostgreSQL,Oracle,SQL Server,Access,达梦数据库
非关系型数据库:
i)面向检索的列式存储 Column-Oriented:HaBase
ii)面向高并发的缓存存储 Key-Value:Redis
iii)面向海量数据访问的文档存储 Document-Oriented:MongoDB
SQL指令不区分大小写,每条指令以分号结束。
查询、创建数据库
修改、删除、使用(切换)数据库
创建数据表
查询、删除数据表
修改数据表
类型 |
内存空间大小 |
范围 |
说明 |
tinyint |
1byte |
有符号 -128~127 无符号 0~255 |
特小型整数(年龄) |
smallint |
2byte |
有符号 -32768~32767 无符号 0~65535 |
小型整数 |
mediumint |
3byte |
有符号 -2^31~2^31-1 无符号 0~2^32-1 |
中型整数 |
int/integer |
4byte |
整数 |
|
bigint |
8byte |
大型整数 |
|
float |
4byte |
单精度 |
|
double |
8byte |
双精度 |
|
decimal |
第一个参数+2 |
decimal(10,2)表示数值一共有10位,小数有2位 |
不包括小数点 |
类型 |
字符长度 |
说明 |
char |
0~255字节 |
定长字符串,最多可以存储255个字符,当我们指定char(n)时,最多存n个字符,如果添加的数据少于n,则补'\u0000'至n长度 |
varchar |
0~65536字节 |
可变长度字符串 |
tinyblob |
0~255 |
存储二进制字符串 |
blob |
0~65535 |
同上 |
mediumblob |
0~1677215 |
同上 |
longblob |
0~4294967295 |
同上 |
tinytext |
0~255 |
文本数据(字符串) |
text |
0~65535 |
同上 |
mediumtext |
0~1677215 |
同上 |
longtext |
0~4294967295 |
同上 |
类型 |
格式 |
说明 |
date |
2023-10-29 |
日期,只存储年月日 |
time |
11:12:13 |
时间,只存储时分秒 |
year |
2023 |
年份 |
datetime |
2023-10-29 11:12:13 |
日期+时间 |
timestamp |
20231029111213 |
时间戳 |
在创建数据表的时候,对数据表的列的数据限制性的要求(对标的列中的数据进行限制),以确保数据的有效性、完整性、正确性。
主键就是数据表中记录的唯一标识,一张表中最多只能有一个主键(主键可以是一列,也可以是多个列的组合,即联合主键)
在创建一张数据表时,如果没有合适的列作为主键时,可以额外定义一个与记录无关的列(ID)做主键,无具体含义,仅作唯一标识。int型,自动增长。
保证唯一性,但不保证连续性。例如有三条信息后,先删除第三条再添加第四条,ID会分别为1,2,4。
不能像定义单个主键那样在后面加上关键字,否则会有多个主键,而不是唯一的。
多条查询语句可以用UNION连接,即是把这些联合成一条查询结果
在删除、修改及查询的语句后都可以添加where子句(条件),用于筛选。
在where子句的条件中,可以使用like关键字来实现模糊查询。
设置查询的列、计算列
as起字段别名
distinct消除重复行
将查询到的满足条件的记录按指定的列的值升序/降序排列
asc升序(默认),desc降序
SQL中提供了一些可以对查询记录的列进行计算的函数——聚合函数
count()统计个数,max()最大值,min()最小值,sum()求和,avg()求平均值
i)日期函数:
在向日期类型的列添加数据时,可以用yyyy-mm-dd hh:mm:ss格式的字符串来赋值
now()获取当前时间,sysdate()系统当前时间
ii)字符串函数:
通过SQL指令对字符串进行处理
concat()拼接,upper()转换为大写输出,lower()转换为小写输出,substring(column,start,len)获取子串,start从1开始
分组——就是将数据表中的记录按照指定的类进行分组
语句执行顺序:①先根据where条件从数据库查询记录,②group by对查询记录进行分组,③执行having对分组后的数据进行筛选。
having关键字
limit(param1,param2):
param1 int,表示查询语句中的第一条数据索引(索引从0开始)
param2 int,便是查询的条数(若剩下的数据小于param2,只返回剩下的所有记录)
人--身份证,学生--学籍,用户--用户详情
方案一:主键关联——两张数据表中主键相同的数据,互为相互对应的数据
方案二:唯一外键关联——在任意一张表中添加有唯一约束的外键约束,与另一张表主键关联
一对多:班级--学生
多对一:学生--班级
方案:在多的一端添加外键,与一的一端主键进行关联
学生--课程,会员--社团
方案:额外创建一张关联关系表——在关系表中定义两个外键分别与两个数据表的主键进行关联
i)外键约束
FK_STUDENTS_CLASSES是外键逻辑名称,可随意起,不用关键字就行。
用insert添加学生时,设置给cid外键列的值必须在其关联的主表classes中class_id列存在。
ii)级联操作
当学生表中存在学生信息关联班级表的某条记录时(被引用),就不能对班级表的这条记录修改ID、删除操作。
如果硬要改,请update表中的相应的内容。
或者使用级联修改ON UPDATE CASCADE 级联删除ON DELETE CASCADE(有点像添加一个特性?)
此后在update时会同步修改,在delete一个时,和它关联的另一个也会被删除。
在MySQL中可以使用join实现多表的联合查询——连接查询,join按其功能不同分为三个操作。
CREATE TABLE if not EXISTS classes(
class_id INT PRIMARY KEY auto_increment,
class_name VARCHAR(40) not null UNIQUE,
class_remark varchar(200)
);
CREATE TABLE if not EXISTS 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) ON UPDATE CASCADE ON DELETE CASCADE
);
insert into classes(class_name,class_remark)VALUES('Java2104','...');
insert into classes(class_name,class_remark)VALUES('Java2105','...');
insert into classes(class_name,class_remark)VALUES('Java2106','...');
insert into classes(class_name,class_remark)VALUES('Python2104','...');
insert into students(stu_num,stu_name,stu_gender,stu_age,cid)VALUES('20210101','张三','男',20,1);
insert into students(stu_num,stu_name,stu_gender,stu_age,cid)VALUES('20210102','李四','女',20,1);
insert into students(stu_num,stu_name,stu_gender,stu_age,cid)VALUES('20210103','王五','男',20,1);
insert into students(stu_num,stu_name,stu_gender,stu_age,cid)VALUES('20210104','赵六','女',20,2);
insert into students(stu_num,stu_name,stu_gender,stu_age,cid)VALUES('20210105','孙七','男',20,2);
insert into students(stu_num,stu_name,stu_gender,stu_age)VALUES('20210106','小红','女',20);
insert into students(stu_num,stu_name,stu_gender,stu_age)VALUES('20210107','小明','男',20);
SELECT * FROM classes;
SELECT * FROM students;
i)笛卡尔积
ii)内连接条件(一般用on设置两张表连接查询的匹配条件)
显示左表中的所有数据,如果在右表中存在与坐标记录满足匹配条件的数据,则进行匹配;如果右表中不存在匹配数据,则显示为null
与左连接类似,显示右表中所有记录
案例1:单行单列,用关系运算符(类似与作为return的值只有一个?)
案例2:单行多列,用IN或NOT IN关键字
案例3:虚拟表(记得起别名)
SQL指令运行过程:
①在navicat中,编写并运行SQL语句②通过数据库连接将SQL指令发送到数据库③接受SQL指令④SQL引擎,编译并执行SQL指令⑤执行的结果通过数据库连接发送到navicat⑥
可能存在的问题:
①如果需要多次重复执行相同的SQL,需要重复执行上述过程,时间开销大。
②如果要连续执行多个SQL指令,且第二个指令需要第一个指令的执行结果作为参数。
存储过程:将能够完成特定功能的SQL指令进行封装(SQL指令集),编译之后存储在数据库端,并为它起一个名字,客户端可以直接通过名字调用这个SQL指令集,获取执行结果。
存储过程优点:
1. SQL指令无需客户端编写,通过网络传送,可以节省网络开销,同时避免SQL指令在网络传输过程中被恶意修改,保证安全性;
2. 存储过程经过编译创建并保存在数据库中的,执行时无需重复的进行编译操作,对SQL指令的执行过程进行了性能提升;
3.存储过程中多个SQL指令之间存在逻辑关系,支持流程控制语句(分支,循环),可以实现更为复杂的业务;
存储过程的缺点:
1.存储过程是根据不同的数据库进行编译,当需要切换到其他的数据库产品时,要重新编写针对于新数据库的存储过程;
2.存储过程受限于数据库产品,如果需要高性能的优化会成为一个问题;
3在互联网项目中,如果带要数据军的高(连接)并发访问,用存储过程会加大数据库的连接执行时间(因为我们将复杂的业务交给了数据库进行处理)
创建:
调用:
局部变量:定义在存储过程中开始的位置,只能在存储过程内部使用
用户变量:相当于全局变量,变量名要以@开始
将查询结果赋值给变量:select...into...
尽量少用用户变量,太多用户变量可能会让代码难以理解。
存储过程参数:MySQL存储过程的参数有三种:IN \ OUT \ INOUT
IN是输入参数,OUT是输出参数,INOUT是同时作为输入和输出参数,但建议少用INOUT,这样会降低代码可读性。
i)分支语句if-then-else
ii)分支语句case
(这里的else有点像C++switch中default?)
iii)循环语句while
iiii)循环语句repeat
iiiii)循环语句loop
i)查询
ii)修改
iii)删除
-- 创建书籍信息表
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('C语言程序设计','Lee',48.80,100,'C语言');
insert into books(book_name,book_author,book_price,book_stock,book_desc)
VALUES('C++快速入门','Zhang',58.80,100,'C++');
-- 创建学生表
CREATE TABLE students(
stu_num char(4) PRIMARY KEY,
stu_name VARCHAR(20) NOT NULL,
stu_gender char(2) NOT NULL,
stu_age int NOT NULL
);
-- 添加学生信息
insert into students(stu_num,stu_name,stu_gender,stu_age)
VALUES('1001','张三','女',20);
INSERT INTO students(stu_num,stu_name,stu_gender,stu_age)
VALUES('1002','李四','男',21);
INSERT INTO students(stu_num,stu_name,stu_gender,stu_age)
VALUES('1003','王五','女',20);
-- 创建借书记录表
CREATE TABLE records(
rid int PRIMARY KEY auto_increment,
snum char(4) not null,
bid int not null,
borrow_num int not null,
is_return int not null, -- 0未归还,1已归还
borrow_date date not null,
CONSTRAINT FK_RECORDS_STUDENTS FOREIGN KEY(snum)REFERENCES students(stu_num),
CONSTRAINT FK_RECORDS_BOOKS FOREIGN KEY(bid)REFERENCES books(book_id)
);
-- 创建存储过程实现借书业务
-- a:学号 b:图书id m:借书数量 state: 1借书成功,2学号不存在,3图书不存在,4库存不足
CREATE PROCEDURE proc_borrow_book(IN a char(4),IN b int,IN m 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_num) INTO stu_count from students WHERE stu_num=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>=m THEN
-- 执行借书,生成记录
insert into records(snum,bid,borrow_num,is_return,borrow_date)
VALUES(a,b,m,0,SYSDATE());
-- 修改库存
UPDATE books SET book_stock=stock-m 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_borrow=-1;
call proc_borrow_book('1001',1,2,@state_borrow);
SELECT @state_borrow FROM DUAL;
-- 还书(健壮性很差,有待完善)
-- 还需要考虑的问题:1.还书数量大于借书数量 2.学号书号不存在 3.等等
CREATE PROCEDURE proc_return_book(IN a char(4),IN b int,IN m int,OUT state int)
-- a:学号 b:图书id m:还书数量 state: 1全还完了,2没还完
BEGIN
DECLARE need_return int DEFAULT 0;
SELECT borrow_num FROM records INTO need_return;
IF m = need_return THEN
UPDATE records SET is_return=1 WHERE snum=a AND bid=b;
UPDATE books SET book_stock=book_stock+m WHERE book_id=b;
SET state=1;
ELSE
UPDATE books SET book_stock=book_stock+m WHERE book_id=b;
SET state=2;
END IF;
END;
SET @state_return=-1;
call proc_return_book('1001',1,2,@state_return);
SELECT @state_return FROM DUAL;
游标可以用来依次取出结果集中的每一条数据——逐条读取查询结果集中的记录(有点像迭代器?)
声明游标:
使用完之后记得关闭游标:CLOSE mycursor;
触发器,是一种特殊的存储过程,但是无需用call来手动调用。当对数据表中的数据执行DML操作时自动会触发。
在MySQL中,只有执行insert\delete\update操作才会触发触发器。
i)案列说明
ii)相关操作
触发器用于监听对数据表中数据的insert\delete\update操作,在触发器中通常处理一些DML的关联操作(如添加日志等);我们可以使用NEW和OLD关键字在触发器中获取触发这个触发器的DML所操作的数据。
NEW:用于获取insert添加的数据,update修改后的记录
OLD:用于获取delete删除的数据,update修改前的记录
以下是上一部分的例子:
视图,就是由数据库中一张表或多张表根据特定的条件查询出的数据构成的虚拟表。
安全性:只向用户开放视图的访问权限,可以有效保护数据表中的数据。
简单性:用户可查询视图来获取多表数据。
视图是虚拟表,其中的数据是来源于原数据表的,在视图中对数据进行操作(比如向视图中加数据、删除视图中数据)时,会对原表有影响。
但是当视图是连接查询的结果的话,是不允许进行删除操作的。
视图的使用建议:对复杂查询进行简化,并且不会对数据进行修改的情况下可以使用视图。
i)修改视图create or replace...
ii)修改视图alter...
iii)删除视图drop(当然不会影响原表中的数据)
事务是一组操作的集合,它是一个不可分割的工作单位,是一系列流程,事务会把所有的操作作为一个整体向系统提交或撤销操作请求。这些操作要么同时成功,要么同时失败。
原子性(Atomicity):多个操作,要么同时成功,要么同时失败。
一致性(Consistency):事务执行前后,数据库中数据是一致的,完整性和一致性不能被破坏。
隔离性(Isolation):数据库允许多个事务同时执行(张三借书时也允许李四借书),多个并行的事务之间不能相互影响。
持久性(Durability):事务完成后,对数据的修改时永久的。
i)自动提交
自动提交:在MySQL中,默认DML指令的执行是自动提交的,当我们执行一个DML指令之后,自动同步到数据库中(先进入连接缓存,然后保存在数据文件)。
ii)事务管理
开启事务start transaction(关闭自动提交),提交事务commit(将连接缓存中的数据存入数据文件),如果在执行的过程中出现异常则回滚rollback,一般会有if..else..判断。
MySQL中,事务隔离级别分为四个:①读未提交②读已提交③可重复读④
i)读未提交(read uncommitted):T2可以读取T1执行但是未提交的数据;可能出现脏读。
ii)读已提交(read committed):T2只能读取T1已经提交的数据;可能虚读(两次读取不一样),也叫不可重复读。
iii)可重复读(repeatable read):T2执行第一次查询之后,在事务结束前其他事务不能修改对应的数据;避免了虚读(不可重复读),但是可能导致幻读(T2对数据表中的数据 进行修改后查询,在查询之前T1向数据表中新增了一条数据,就导致T2以为修改了所有数据,但却查询出了与修改不一致的数据(T1事务新增的数据))
iiii)串行化(serializable):同时只允许一个事务对数据表进行操作;避免了脏读,虚读和幻读。
隔离级别 |
脏读 |
虚读 |
幻读 |
read uncommitted |
√ |
√ |
√ |
read committed |
× |
√ |
√ |
repeatable read |
× |
× |
√ |
serializable |
× |
× |
× |
MySQL默认的隔离级别是可重复读,可能幻读。
i)查看MySQL默认隔离级别
ii)设置MySQL默认隔离级别
索引(index)是帮助MySQL高效获取数据的数据结构(有序),取出数据表中的一列或多列构造成便于查找的结构,生成数据表的目录。
i)主键索引:在数据表中的主键字段创建索引,这个字段必须被primary key修饰,每张表只能有一个主键。
ii)唯一索引:在数据表中的唯一列创建的索引(unique),此列的所有值只能出现依次,可以为NULL。
iii)普通索引:在普通字段上创建的索引,没有唯一性的限制。
iiii)组合索引:两个及以上字段联合起来创建索引。
说明:建表时,主键和唯一键都会默认生成索引。
i)唯一索引
只要这一列的值没有重复,即可以创建唯一索引。
ii)普通索引和组合索引
iii)全文索引
创建过索引之后,无需调用,当根据创建索引的列进行查询时,自动触发。(组合索引需要同时que到其中所有的字段来进行查询才会触发)
i)查询索引的规划(有点查看详情的意味)
i)查看
ii)删除