补充内容
1.数据完整性
3.有主外键关联表,先删外键表数据,再删除主键表数据
数据库
数据库、数据表、数据之间的关系
DDL 操作数据库和数据表
/*
查询所有数据库
-- 标准语法:
SHOW DATABASES;
*/
SHOW DATABASES;
/*
查询某个数据库的创建语句
标准语法:
SHOW CREATE DATABASE 数据库名称
*/
SHOW CREATE DATABASE mysql;
/*
创建数据库
标准语法:
CREATE DATABASE 数据库名称;
*/
-- 创建0809开始自学的数据库内容
CREATE DATABASE case0806;
/*
为了避免出现上面数据库创建语句,如果重复时,创建报错,
故使用下面的数据库创建语句来避免出现这种错误出现,
下面语句执行后,若存在同样的数据库,便只是会出现警告
并不会报错
创建数据库,判断、如果不存在则创建
标准语法:
CREATE DATABASE IF NOT EXISTS 数据库名称;
*/
CREATE DATABASE IF NOT EXISTS case0806;
/*
创建数据库,并指定字符集
标准语法:
CREATE DATABASE 数据库名称 CHARACTER SET 字符集名称;
*/
CREATE DATABASE case0806 CHARACTER SET utf8;
-- 查看数据库的字符集
SHOW CREATE DATABASE case0806;
CREATE DATABASE IF NOT EXISTS case0806 CHARACTER SET utf8;
SHOW CREATE DATABASE case0806;
/*
修改数据库的字符集
ALTER DATABASE 数据库名称 CHARACTER SET 字符集名称;
*/
ALTER DATABASE case0806 CHARACTER SET gbk;
SHOW CREATE DATABASE case0806;
ALTER DATABASE case0806 CHARACTER SET utf8;
/*
删除数据库:
DROP DATABASE 数据库名称;
*/
DROP DATABASE case0806;
/*
删除数据库,判断、如果存在则删除:(与前面的创建数据库类似)
DROP DATABASE IF EXISTS 数据库名称;
*/
DROP DATABASE IF EXISTS db2;
/*
使用数据库
USE 数据库名称;
*/
USE case0806;
/*
查询当前使用的数据库
SELECT DATABASE();
*/
SELECT DATABASE();
-- 操作数据表
-- 使用mysql数据库
USE mysql;
/*
查询所有的数据表
SHOW TABLES;
*/
SHOW TABLES;
/*
查询表结构:
DESC 表名;
*/
-- 查询库中所有的表
DESC USER;
/*
查询数据表的字符集
SHOW TABLE STATUS FROM 数据库名称 LIKE '表名';
*/
SHOW TABLE STATUS FROM mysql LIKE 'user';
/*
创建数据表
CREATE TABLE 表名(
列名 数据类型 约束,
列名 数据类型 约束,
...
列名 数据类型 约束
);
*/
CREATE TABLE product(
id INT,
NAME VARCHAR(20),
price DOUBLE,
stock INT,
insert_time DATE
);
-- 查询库中所有的表
DESC product;
-- 修改数据表
/*
修改表名
ALTER TABLE 旧表名 RENAME TO 新表名;
*/
ALTER TABLE product RENAME TO product2;
/*
修改表的字符集
ALTER TABLE 表名 CHARACTER SET 字符集名称;
*/
SHOW TABLE STATUS FROM case0806 LIKE 'product';
ALTER TABLE product CHARACTER SET gbk;
/*
单独添加一列
ALTER TABLE 表名 ADD 列名 数据类型;
*/
ALTER TABLE product ADD color VARCHAR(10);
/*
修改某列的数据类型
ALTER TABLE 表名 MODIFY 列名 新数据类型;
*/
ALTER TABLE product MODIFY color INT;
DESC product;
/*
修改列名和数据类型
ALTER TABLE 表名 CHANGE 列名 新列名 新数据类型;
*/
ALTER TABLE product CHANGE color address VARCHAR(200);
/*
删除某一列
ALTER TABLE 表名 DROP 列名;
*/
ALTER TABLE product DROP address;
-- 数据表删除
/*
DROP TABLE 表名;
*/
DROP TABLE product;
/*
删除数据表(判断,如果存在则删除)
DROP TABLE IF EXISTE 表名;
*/
DROP TABLE IF EXISTS product;
DML 表数据的增删改
-- 新增表数据
-- 列名和值的数量以及数据类型要对应,除了数字类型,其他数据类型的数据都需要加引号(单弓双引都行,推荐单引)。
/*
给指定列添加数据
INSERT INTO 表名(列名1,列名2,...) VALUES(值1,值2,...);
*/
INSERT INTO product(id,NAME,price,stock,insert_time) VALUES (1,'qq',1999.99,25,'2020-02-02');
INSERT INTO product (id,NAME,price) VALUES (2,'但是',3999.99);
/*
给全部列添加数据
INSERT INTO 表名 VALUES(值1,值2,...);
*/
INSERT INTO product VALUES (3,'冰袖',1500,35,'2030-02-03');
/*
批量添加数据
INSERT INTO 表名(列名1,列名2,...) VALUES(值1,值2,...),(值1,值2,...),...;
INSERT INTO 表名 VALUES(值1,值2,...),(值1,值2,...),...;
*/
-- 修改和删除表数据
/*
修改表中的数据
UPDATE 表名 SET 列名1=值1,列名2=值2,...[WHERE 条件];
中括号表示可选,可以有where也可以没有,在这里需要有,因为没有的话会删除全部的数据
修改语句中必须加条件,如果不加条件,则会将所有数据都修改。
*/
UPDATE product SET price=3500 WHERE NAME='qq';
UPDATE product SET price=1800,stock=36 WHERE NAME='但是';
/*
删除表中的数据
DELETE FROME 表名 [WHERE 条件];
删除语句中必须加条件,如果不加条件,则会将所有数据都删除。
*/
DELETE FROM product WHERE NAME='但是';
DELETE FROM product WHERE stock=25;
DQL表数据的查询
条件查询
-- 条件查询
SELECT * FROM product WHERE stock > 20;
SELECT * FROM product WHERE NAME='冰袖';
SELECT * FROM product WHERE price >= 400 AND price <= 6000;
SELECT * FROM product WHERE price BETWEEN 4000 AND 6000;
SELECT * FROM product WHERE stock = 14 OR stock=30 OR stock=23;
SELECT * FROM product WHERE stock IN(14,30,23);
SELECT * FROM product WHERE stock IS NULL;
SELECT * FROM product WHERE stock IS NOT NULL;
-- 查询名称以冰开头的商品信息
SELECT * FROM product WHERE NAME LIKE '冰%';
-- 查询名称第二个字是袖的商品信息
SELECT * FROM product WHERE NAME LIKE '_袖%';
-- 查询名称为4个字符的商品信息
SELECT * FROM product WHERE NAME LIKE '____';
-- 查询名称中包含电脑的商品信息
SELECT * FROM product WHERE NAME LIKE '%电脑%';
聚合函数查询
-- 聚合函数查询
-- 计算product表中总记录条数
SELECT COUNT(*) FROM product;
-- 获取最大值
SELECT MAX(price) FROM product;
SELECT MIN(stock) FROM product;
-- 获取总库存数量
SELECT SUM(stock) FROM product;
-- 获取name为冰袖的总库存数量
SELECT SUM(stock) FROM product WHERE NAME='冰袖';
SELECT AVG(price) FROM product WHERE NAME='冰袖';
排序查询
-- 排序查询
/*
排序查询语法
SELECT
列名列表
FROM
表名
[WHERE 条件]
ORDER BY
列名 排序方式,
列名 排序方式,...
排序方式: ASC升序,DESC-降序
如果有多个排序条件,只有当前边的条件值一样时,才会判断第二条件。
*/
-- 按照库存升序排序
SELECT * FROM product ORDER BY stock ASC;
-- 按照金额降序排序
SELECT * FROM product WHERE NAME LIKE '%手机%' ORDER BY price DESC;
-- 按照金额升序排序,如果金额相同,再按照库存降序排序
SELECT * FROM product ORDER BY price ASC,stock DESC;
分组查询
-- 分组查询
/*
如果有条件,一定是先进行条件判断
分组查询语法
SELECT 列名列表 FROM 表名 [WHERE 条件] GROUP BY 分组列名
[HAVING 分组后的条件过滤]
[ORDER BY 排序列名 排序方式]
*/
-- 按照品牌分组,获取每组商品的总金额
SELECT brand,SUM(price) FROM product GROUP BY brand;
-- 对金额大于4000元的商品,按照品牌分组,获取每组商品的总金额
seelct brand,SUM(price) FROM product WHERE price > 4000 GROUP BY brand;
-- 对金额大于4000元的商品,按照品牌分组,获取每组商品的总金额,只显示总金额大于7000元的
SELECT brand,SUM(price) getSum FROM product WHERE price > 4000 GROUP BY brand HAVING getSum > 7000;
-- 对金额大于4000元的商品,按照品牌分组,获取每组商品的总金额,只显示总金额大于7000元的、并按照总
SELECT brand,SUM(price) getSUm FROM product
WHERE price > 4000
GROUP BY brand
HAVING getSum > 7000
ORDER BY getSum DESC;
分页查询
-- 分页查询
/*
分页查询语法
SELECT 列名列表 FROM 表名
[WHERE 条件]
[GROUP 分组列名]
[HAVING 分组后的条件过滤]
[ORDER BY 排序列名 排序方式]
LIMIT 当前页数,每页显示的条数;
LIMIT 当前页数,每页显示的条数;
公式:当前页数=(当前页数-1) * 每页显示的条数
*/
-- 每页显示3条数据 如果一共7条数据
-- 第一页 当前页数=(1-1) * 3
SELECT * FROM product LIMIT 0,3;
-- 第二页 当前页数=(2-1) * 3
SELECT * FROM product LIMIT 3,3;
-- 第三页 当前页数=(3-1) * 3
SELECT * FROM product LIMIT 6,3;
-- ......
约束
唯一约束:
非空约束:
主键约束:
主键一般用于表中数据的唯一标识。不能为null值
主键自增约束:
外键约束:
让表与表之间产生关联关系,从而保证数据的准确性!
外键级联更新/删除
了解
多表操作
多表概念:说白了就是多张数据表,而表与表之间是可以有一定的关联关系 ,这种关联关系通过外键约束实现。
一对一
适用场景:
人和身份证。一个人只有一个身份证,一个身份证只能对应一个人。
建表原则:
在任意一个表建 立外键,去关联另外-一个表的主键。
ALTER TABLE orderlist ADD
CONSTRAINT ou_fk2 FOREIGN KEY orderlist(uid) REFERENCES USER(id)
ON UPDATE CASCADE;
一对多
适用场景
用户和订单。一个用户可以多个订单。
商品分类和商品。一个分类下可以有多个商品。
建表原则
在多的一方,建立外键约束,来关联一的一方主键。
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT, -- 主键id
NAME VARCHAR(20) -- 姓名
);
INSERT INTO USER VALUES (NULL,'张三'),(NULL,'李四');
-- 创建orderlist表
CREATE TABLE orderlist(
id INT PRIMARY KEY AUTO_INCREMENT, -- 主键id
number VARCHAR(20), -- 订单编号
uid INT, -- 外键列
CONSTRAINT ou_fk1 FOREIGN KEY (uid) REFERENCES USER(id)
);
多对多
适用场景
学生和课程。一个学生可以选择多个课程,一个课程也可以被多个学生选择。
建表原则
需要借助第三张中间表,中间表至包含两个列。这两个列作为中间表的外键,分别关联两张表的主键。
多表查询
内连接查询
-- 内连接
-- 查询的是相关的数据表之间有交集的那部分的数据,也就是有外键关系的数据
/*
显示内连接
SELECT 列名 FROM 表名1 [INNER] JOIN 表名2 ON 关联条件;
*/
-- 查询用户信息和对应的订单信息
SELECT * FROM USER INNER JOIN orderlist ON orderlist.uid = user.id;
-- 查询用户信息和对应的订单信息,起别名
SELECT * FROM USER u INNER JOIN orderlist o ON o.uid = u.id;
-- 查询用户姓名,年龄。和订单编号
SELECT
u.name,
u.age,
o.number
FROM
USER u
INNER JOIN
orderlist o
ON
o.uid = u.id;
/*
隐式内连接
标准语法:
SELECT 列名 FROM 表名1,表名2 WHERE 关联条件;
*/
-- 查询用户姓名,年龄。和订单编号
SELECT
u.name,
u.age,
o.number
FROM
USER u,
orderlist o
WHERE
o.uid = u.id;
外连接查询
-- 左外连接
-- 查询所有用户信息,以及用户对应的订单信息
SELECT
u.*,
o.number
FROM
USER u
LEFT OUTER JOIN
orderlist o
ON
o.uid=u.id;
-- 右外连接
-- 查询所有订单信息,以及订单所属的用户信息
SELECT
o.*,
u.name
FROM
USER u
RIGHT OUTER JOIN
orderlist o
ON
o.uid = u.id;
子查询
-- 结果是单行单列的
-- 查询年龄最高的用户姓名
SELECT NAME,age FROM USER WHERE age=(SELECT MAX(age) FROM USER);
-- 结果是多行多列的
-- 查询张三1和张三2的订单信息
SELECT * FROM orderlist WHERE uid IN (1,2);
SELECT id FROM USER WHERE NAME IN ('张三1','张三2');
SELECT * FROM orderlist WHERE uid IN (SELECT id FROM USER WHERE NAME IN ('张三1','张三2'));
-- 查询订单表中id大于4的订单信息和所属用户信息
SELECT * FROM orderlist WHERE id > 4;
SELECT
u.name,
o.number
FROM
USER u,
(SELECT * FROM orderlist WHERE id > 4) o
WHERE
u.id = o.uid;
自关联查询
在同一张表中数据有关联性,我们可以把这张表当成多个表来查询。
-- 创建员工表
CREATE TABLE employee(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
mgr INT,
salary DOUBLE
);
-- 添加数据
INSERT INTO employee VALUES (1001,'孙悟空',1005,9000.0),
(1002,'沙和尚',1005,8000.00),
(1003,'猪八戒',1005,8500.00),
(1004,'小白龙',1005,7900.00),
(1005,'唐僧',NULL,18000.00),
(1006,'李逵',1009,8500.00),
(1007,'林冲',1009,7900.00),
(1008,'武松',1009,8100.00),
(1009,'宋江',NULL,16000.00);
-- mgr上级编号,mgr=1005,表示他们的上级都是唐僧,唐僧的mgr为null,没有上级
-- 1009类似
-- 查询所有员工的姓名及其直接上级的姓名,没有上级的员工也需要查询
/*
员工信息:employee表
条件:employee.mgr = employee.id
查询左表的全部数据,和左右两张表有交集部分数据,左外连接
*/
SELECT
e1.id,
e1.name,
e1.mgr,
e2.id,
e2.name
FROM
employee e1
LEFT OUTER JOIN
employee e2
ON
e1.mgr = e2.id;
练习
-- 1.查询用尸的编号、姓名、年龄。订单编号
/*
user表、orderlist表
条件:user.id=orderlist.uid
*/
SELECT
u.id,
u.name,
u.age,
o.number
FROM
USER u,
orderlist o
WHERE
u.id = o.uid;
-- 2.查询所有的用户。用户的编号、姓名、年龄。订单编号
/*
外连接
*/
SELECT
u.id,
u.name,
u.age,
o.number
FROM
USER u
LEFT OUTER JOIN
orderlist o
ON
u.id=o.uid;
-- 3.查询所有的订单。用户的编号、姓名、年龄。订单编号
/*
右外连接
*/
SELECT
u.id,
u.age,
u.name,
o.number
FROM
USER u
RIGHT OUTER JOIN
orderlist o
ON
u.id=o.uid;
-- 4.查询用户年龄大于23岁的信息。显示用户的编号、姓名、年龄。订单编号
/*
user orderlist
条件:user.id=o.uid and u.age>23
*/
SELECT
u.id,
u.age,
u.name,
o.number
FROM
USER u,
orderlist o
WHERE
u.age>23 AND u.id=o.uid;
-- 5.查询张三和李四用户的信息。显示用户的编号、姓名、年龄。订单编号
/*
user orderlist
条件:user.id=orderlist.uid and user.name in ('张三','李四');
*/
SELECT
u.id,
u.age,
u.name,
o.number
FROM
USER u,
orderlist o
WHERE
u.id=o.uid
AND
u.name IN ('张三1','张三2');
-- 6.查询商品分类的编号、分类名称。分类下的商品名称
/*
category product
条件:category.id = product.cid
*/
SELECT
c.id,
c.name,
p.name
FROM
category c,
product p
WHERE
c.id=p.cid;
-- 7.查询所有的商品分类。商品分类的编号、分类名称。分类下的商品名称
/*
category product
条件:category.id=product.cid
左外连接
*/
SELECT
c.id,
c.name,
p.name
FROM
category c
LEFT OUTER JOIN
product p
ON
c.id=p.cid;
-- 8.查询所有的商品信息。商品分类的编号、分类名称。分类下的商品名称
SELECT
c.id,
c.name,
p.name
FROM
category c
RIGHT OUTER JOIN
product p
ON
c.id=p.cid;
-- 9.查询所有的用户和该用户能查看的所有的商品。显示用户的编号、姓名、年龄。商品名称
/*
user product 多对多关系,所以还需要查询 us_pro
条件:us_pro.uid=user.id and us_pro.pid=peoduct.id
*/
SELECT
u.id,
u.name,
u.age,
p.name
FROM
USER u,
product p,
us_pro up
WHERE
up.uid=u.id
AND
up.pid=p.id;
-- 10.查询张三和李四这两个用户可以看到的商品。显示用户的编号、姓名、年龄。商品名称
/*
user product us_pro
条件:us_pro.uid=user.id and us_pro.pid=product.id and user.name in ('张三1','张三2');
*/
SELECT
u.id,
u.name,
u.age,
p.name
FROM
USER u,
product p,
us_pro up
WHERE
up.uid=u.id
AND
up.pid=p.id
AND
u.name IN ('张三1','张三2');
视图
视图:是一种虚拟存在的数据表,这个虚拟表并不在数据库中实际存在。
作用:将一些较为复杂的查询语句的结果,封装到一个虚拟表中,后期再有相同需求时,直接查询该虚拟表即可。
视图的创建和查询
-- 视图
CREATE DATABASE db0809pm;
USER db0809pm;
CREATE TABLE country(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(30)
);
INSERT INTO country VALUES (NULL,'中国'),(NULL,'美国'),(NULL,'俄罗斯');
CREATE TABLE city(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(30),
cid INT,`country`
CONSTRAINT cc_fk1 FOREIGN KEY (cid) REFERENCES country(id)
);
INSERT INTO city VALUES (NULL,'beijing',1),(NULL,'shanghai',1),(NULL,'niuy',2),(NULL,'莫斯科',3);
-- 创建city_ country视图,保存城市和国家的信息(使用指定列名)
CREATE VIEW city_country (city_id,city_name,country_name) AS
SELECT
c1.id,
c1.name,
c2.name
FROM
city c1,
country c2
WHERE
c1.id=c2.id;
-- 查询视图
SELECT * FROM city_country;
视图的修改和删除
-- 修改视图数据,将北京修改为深圳。(注意:修改视图数据后,源表中的数据也会随之修改)
UPDATE city_country SET city_name='深圳' WHERE city_name='beijing';
-- 将视图中的country_ name修 改为name
ALTER VIEW city_country (city_id,city_name,NAME) AS
SELECT
c1.id,
c1.name,
c2.name
FROM
city c1,
country c2
WHERE
c1.id=c2.id;
-- 删除视图
DROP VIEW IF EXISTS city_country;
数据库备份和恢复
MySQL存储过程和函数
存储过程和函数是事先经过编译并存储在数据库中的一段SQL语句的集合。
存储过程和函数的好处
提高代码的复用性。
减少数据在数据库和应用服务器之间的传输,提高效率。
减少代码层面的业务处理。
类似与java中的方法
存储过程和函数的区别
存储函数必须有返回值。
存储过程可以没有返回值。
存储过程的创建和调用
CREATE TABLE student(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
age INT,
gender VARCHAR(5),
score INT
);
INSERT INTO student VALUES(NULL,'张三',23,'男',95),(NULL,'lisi',24,'男',98),
(NULL,'wangwu',25,'女',100),(NULL,'zhaoliu',26,'女',90);
-- 按照性别进行分组,查询每组学生的总成绩。按照总成绩的升序排序
SELECT gender,SUM(score) getSum FROM student GROUP BY gender ORDER BY getSum ASC;
-- 创建stu_ group()存储过程,封装分组查询总成绩,并按照总成绩升序排序的功能
DELIMITER $
CREATE PROCEDURE stu_group()
BEGIN
SELECT gender,SUM(score) getSum FROM student GROUP BY gender ORDER BY getSum ASC;
END$
DELIMITER ;
-- 调用stu_ group()存储过程
CALL stu_group();
储存过程的查看和删除
-- 杳看db6数掘库中所有的存储讨程
SELECT * FROM mysql.proc WHERE db='db0809pm';
-- 删除储存过程
DROP PROCEDURE IF EXISTS stu_group;
存储过程语法
变量
-- 定义一个int类型变量,并赋默认值为10
DELIMITER $
CREATE PROCEDURE pro_test1()
BEGIN
-- 定义变量
DECLARE num INT DEFAULT 10;
-- 使用变量
SELECT num;
END$
DELIMITER ;
-- 调用pro_ test1存 储过程
CALL pro_test1();
-- 定义一个varchar类型变量并赋值
DELIMITER $
CREATE PROCEDURE pro_test2()
BEGIN
-- 定义变量
DECLARE NAME VARCHAR(10);
-- 为变量赋值
SET NAME = '存储过程';
-- 使用变量
SELECT NAME;
END$
DELIMITER ;
-- 调用pro_ test2存 储过程
CALL pro_test2();
-- 定义两个Int变量,用于存储男女同学的总分数
DELIMITER $
CREATE PROCEDURE pro_test3()
BEGIN
-- 定义两个变量
DECLARE men,women INT;
-- 查询男同学的总分数,为men赋值
SELECT SUM(score) INTO men FROM student WHERE gender='男';
-- 查询女同学的总分数,为women赋值
SELECT SUM(score) INTO women FROM student WHERE gender='女';
-- 使用变量
SELECT men,women;
END$
DELIMITER ;
-- 调用pro_ test3存 储过程
CALL pro_test3();
if语句
/*
定义一个int变量,用于存储班级总成绩
定义一个varchar变量,用于存储分数描述
根据总成绩判断:
380分及以上 学习优秀
320 ~ 380 学习不错
320以下 学习一般
*/
DELIMITER $
CREATE PROCEDURE pro_test4()
BEGIN
-- 定义变量
DECLARE total INT;
DECLARE info VARCHAR(10);
-- 查询总成绩,为total赋值
SELECT SUM(score) INTO total FROM student;
-- 对总成绩判断
IF total > 380 THEN
SET info = '学习优秀';
ELSEIF total >= 320 AND total <= 380 THEN
SET info = '学习不错';
ELSE
SET info = '学习一般';
END IF;
-- 查询总成绩和描述信息
SELECT total,info;
END$
DELIMITER ;
-- 调用pro_test4储存过程
CALL pro_test4();
参数传递
/*
输入总成绩变量,代表学生总成绩
输出分数描述变量,代表学生总成绩的描述信息
根据总成绩判断:
380分及以上 学习优秀
320 ~ 380 学习不错
320以下 学习一般
*/
DELIMITER $
CREATE PROCEDURE pro_test5(IN total INT,OUT info VARCHAR(10))
BEGIN
-- 对总成绩判断
IF total > 380 THEN
SET info = '学习优秀';
ELSEIF total >= 320 AND total <= 380 THEN
SET info = '学习不错';
ELSE
SET info = '学习一般';
END IF;
END$
DELIMITER ;
-- 调用pro test5存 储过程
CALL pro_test5(383,@info);
CALL pro_test5((SELECT SUM(score) FROM student),@info);
SELECT @info;
while循环
-- 计算1~100之间的偶数和
DELIMITER $
CREATE PROCEDURE pro_test6()
BEGIN
-- 定义求和变量
DECLARE result INT DEFAULT 0;
-- 定义初始化变量
DECLARE num INT DEFAULT 1;
-- while循环
WHILE num <= 100 DO
IF num % 2 = 0 THEN
SET result = result + num;
END IF;
SET num = num+1;
END WHILE;
-- 查询求和结果
SELECT result;
END$
DELIMITER ;
-- 调用pro_ test6存 储过程
CALL pro_test6();
存储函数
-- 定义存储函数,获取学生表中成绩大于95分的学生数量
DELIMITER $
CREATE FUNCTION fun_test1()
RETURNS INT
BEGIN
-- 定义变量
DECLARE s_count INT;
-- 查询成绩大于95分的数量,为s_count赋值
SELECT COUNT(*) INTO s_count FROM student WHERE score>95;
-- 返回统计结果
RETURN s_count;
END$
DELIMITER ;
-- 调用函数
SELECT fun_test1();
-- 删除函数
DROP FUNCTION fun_test1;
触发器
操作触发器
insert触发器
-- 触发器
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
money DOUBLE
);
-- insert into account values (null,'zhangsan',1000),(null,'lisi',1000);
-- 创建日志表account_log
CREATE TABLE account_log(
id INT PRIMARY KEY AUTO_INCREMENT, -- 日志id
operation VARCHAR(20), -- 操作类型
operation_time DATETIME,
operation_id INT, -- 操作表的id
operation_params VARCHAR(200) -- 操作参数
);
-- 创建INSERT型触发器。用于对account表新增数据进行日志的记录’
DELIMITER $
CREATE TRIGGER acccount_insert
AFTER INSERT
ON account
FOR EACH ROW
BEGIN
INSERT INTO account_log VALUES (NULL,'INSERT',NOW(),new.id,CONCAT('插入后{id=',new.id,',name=',new.name,',money=',new.money,'}'));
END$
DELIMITER ;
-- 向account表添加一条记录
INSERT INTO account VALUES (NULL,'wangwu',2000);
-- 查询account表
SELECT * FROM account;
-- 查询account_ log表
SELECT * FROM account_log;
update触发器
-- 创建UPDATE型触发器。用于对account表修改数据进行日志的记录
DELIMITER $
CREATE TRIGGER account_update
AFTER UPDATE
ON account
FOR EACH ROW
BEGIN
INSERT INTO account_log VALUES (NULL,'UPDATE',NOW(),new.id,CONCAT('更新前{id=',old.id,',name=',old.name,',money=',old.money,'}','更新后{id=',new.id,',name=',new.name,',money=',new.money,'}'));
END$
DELIMITER ;
UPDATE account SET money=2000 WHERE account.name='lisi';
SELECT * FROM account;
SELECT * FROM account_log;
delete触发器
-- 创建DELETE型触发器。用于对account表删除数据进行日志的记录
DELIMITER $
CREATE TRIGGER account_delete
AFTER DELETE
ON account
FOR EACH ROW
BEGIN
INSERT INTO account_log VALUES (NULL,'DELETE',NOW(),old.id,CONCAT('删除前{id=',old.id,',name=',old.name,',money=',old.money,'}'));
END$
DELIMITER ;
DELETE FROM account WHERE account.name='wangwu';
SELECT * FROM account;
SELECT * FROM account_log;
查看/删除触发器
-- 查看触发器
SHOW TRIGGERS;
-- 删除acccount_insert触发器
DROP TRIGGER acccount_insert;
事务
事务:一条或多条SQL语句组成一一个执行单元,其特点是这个单元要么同时成功要么同时失败。
单元中的每条SQL语句都相互依赖,形成一个整体。
如果某条SQL语句执行失败或者出现错误,那么整个单元就会撤回到事务最初的状态。
如果单元中所有的SQL语句都执行成功,则事务就顺利执行。
事务的操作
开启事务:
START TRANSACTION;
回滚事务:
ROLLBACK;
提交事务:
COMMIT;
-- 事务
-- 张三个李四转账500
-- 开启事务
START TRANSACTION;
-- zhangsan-500
UPDATE account SET money=money-500 WHERE NAME='zhangsan';
-- chucuo
-- 暂时储存,如果不提交,关闭mysql连接过后再重新打开,数据库里面的数据不会发生变化
-- lisi+500
UPDATE account SET money=money+500 WHERE NAME='lisi';
-- 回滚事务
ROLLBACK;
-- 提交事务
COMMIT;
事务的提交方式
事务提交方式的分类
自动提交(MySQL默认)。
手动提交。
查看事务提交方式
SELECT @@AUTOCOMMIT;
修改事务提交方式
SET @@AUTOCOMMIT=数字;
/*
查询事务提交方式: SELECT @@AUTOCOMMIT;
1代表自动提交 0代表手动提交
修改事务提交方式:SET @QAUTOCOMMIT=数字;
*/
-- 查询事务的提交方式
SELECT @@autocommit;
-- 修改事务的提交方式
SET @autocommit = 0;
事务的四大特征
原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚。
因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
一致性(Consistency)
一致性是指事务必须使数据库从一一个一致性状态变换到另一个一 致性状态。
也就是说一个事务执行之 前和执行之后都必须处于致性状态。
隔离性(isolcation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时 ,数据库为每一个用户开启事务。
不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
持久性(durability)
持久性是指一个事务一-旦被提交 了, 那么对数据库中的数据的改变就是永久性的。
即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
事务的隔离级别
-- 查询事务隔离级别
SELECT @@tx_isolation;
-- 修改事务隔离级别(修改后需要重新连接)
SET clobal TRANSACTION ISOLATION LEVEL READ COMMITTED;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yhjyXnBr-1628603928108)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20210810121655957.png)]
存储引擎
MySQL数据库使用不同的机制存取表文件,包括存储方式、引技巧、锁定水平等不同的功能。这些不同的技术以及配套的功能称为存储弓|擎。
Oracle、SqIServer 等数据库只有一种存储引擎。而MySQL针对不同的需求,配置不同的存储引擎就会让数据库采取不同处理数据的方式和扩展功能。
MySQL支持的存储引擎有很多, 常用的有三种: InnoDB、MyISAM、 MEMORY。
特性对比
MylSAM存储引擎:访问快,不支持事务和外键操作。
InnoDB存储引擎:支持事务和外键操作,支持并发控制,占用磁盘空间大。(MySQL 5.5版本后默认)
MEMORY存储引擎:内存存储,速度快,不安全。适给小量快速访问的数据。
存储引擎的操作
SHOW ENGINES;
SHOW TABLE STATUS FROM db0809pm;
SHOW TABLE STATUS FROM db0809pm WHERE NAME = 'account';
CREATE TABLE engine_test(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10)
)ENGINE = INNODB;
ALTER TABLE engine_test ENGINE = MYISAM;
存储引擎的选择
MyISAM
特点:不支持事务和外键操作。读取速度快,节约资源。
使用场景:以查询操作为主,只有很少的更新和删除操作,姐对事务的完整性、并发性要求不是很高!
InnoDB
特点: MySQL的默认存储引擎,支持事务和外键操作。
使用场景:对事务的完整性有比较高的要求,在并发条件下要求数据的一致性,读写频繁的操作!
MEMORY
特点:将所有数据保存在内存中,在需要快速定位记录和其他类似数据环境下,可以提供更快的访问。
使用场景:通常用于更新不太频繁的小表,用来快速得到访问的结果!
总结:针对不同的需求场景,来选择最适合的存储|擎即呵!如果不确定、则使用数据库默认的存储引擎!
索引
MySQL索引:是帮助MySQL高效获取数据的一种数据结构。所以,索引的本质就是数据结构!
在表数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就可以**在这些数据结构上实现高级查找算法,**这种数据结构就是索引。
按照功能分类
普通索引:最基本的索引,没有任何限制。
唯一索引:索引列的值必须唯- , 但允许有空值。如果是组合索引,则列值组合必须唯一。
主键索引:一种特殊的唯一引, 不允许有空值。在建表时有主键列同时创建主键索弓l。
联合索列:顾名思义,就是将单列索弓l进行组合。
外键索引:只贿InnoDB引擎支持外键索引,用来保证数据的一致性、完整性和实现级联操作。
全文索引:快速匹配全部文档的方式。InnoDB 引擎5.6版本后才支持全文索引。MEMORY 引擎不支持。
按照结构分类
BTree索引: MySQL使用最频繁的一个索|数据结构,是InnoDB和MylSAM存储弓|擎默认的索|类型,底层基于B+Tree数据结构。
Hash索引: MySQL中Memory存储引擎默认支持的索引类型。
索引的操作
创建查询索引
-- 为student表中的name列创建一个普通索引
CREATE INDEX idx_name ON student(NAME);
-- 为student表中的age列创建一个唯一索引
CREATE UNIQUE INDEX idx_age ON student(age);
-- 查询student表中的索引 (主键列目带主键索引)
SHOW INDEX FROM student;
-- 查询db0809数据库中的product表(外键列自带外键索引)
SHOW INDEX FROM product;
添加删除索引
索引的原理
索引是在存储引擎中实现的,不同的存储弓擎所支持的索引也不一样,这里我们主要介绍InnoDB引擎的BTree索引。
BTree索引类型是基于B+Tree数据结构的,而B+Tree数据结构又是BTree数据结构的变种。通常使用在数据库和操作系统中的文件系统,特点是能够保持数据稳定有序。
需要理解的B+Tree和BTree的区别
磁盘存储
系统从磁盘读取数据到内存时是以磁盘块( block )为基本单位的。
位于同一个磁盘块中的数据会被一次性读取出来 ,而不是需要什么取什么。
InnoDB存储引擎中有页( Page )的概念,页是其磁盘管理的最小单位。InnoDB 存储弓|擎中默认每个页的大小为16KB。
InnoDB弓|擎将若干个地址连接磁盘块,以此来达到页的大小16KB ,在查询数据时如果一个页中的每条数据都能有 助于定位
数据记录的位置,这将会减少磁盘I/O次数,提高查询效率。
BTree
在每一个结点上除了去保存键值以外,还会去保存真实的数据,在进行查询数据时,只要涉及到相应的磁盘块,那这些数据也会被全部读取出来,所以效率不是很高。
B+Tree
B+Tree特点:在分支结点上只保存键值,并没有真实的数据,真实的数据只会保存在叶子结点上
在磁盘块上并没有涉及到IO操作,提高了查询的特点
叶子结点之间进行连接,方便进行范围的查询
BTree数据结构
每个节点中不仅包含key值,还有数据。会增加查询数据时磁盘的I0次数。
B+Tree数据结构
非叶子节点只存储key值。
所有数据存储在叶子节点。
所有叶子节点之间都有连接指针。
B+Tree好处
提高查询速度。
减少磁盘的I0次数。
树型结构较小。
索引的设计原则
创建索引遵循的原则
1.对查询频次较高,且数据量比较大的表建立索弓|。
2.使用唯一索引,区分度越高,使用索引|的效率越高。
3.索引字段的选择,最佳候选列应当从where子句的条件中提取。
4.虽然可以有效的提升查询数据的效率 ,但并不是多 多益善。
锁
锁机制:数据库为了保证数据的一致性,在共享的资源被并发访问时变得安全所设计的一种规则。
锁机制类似多线程中的同步,作用就是可以保证数据的一致性和安全性。
按操作分类
共享锁:也叫读锁。针对同一份数据,多个事务读取操作可以同时加锁而不互相影响, 但是不能修改数据。
排他锁:也叫写锁。当前的操作没有完成前,会阻断其他操作的读取和写入。
按粒度分类
表级锁:会锁定整个表。开销小,加锁快。锁定力度大,发生锁冲突概率高,并发度低。不会出现死锁情况。
行级锁:会锁定当前行。开销大,加锁慢。锁定粒度小,发生锁冲突概率低,并发度高。会出现死锁情况。
按使用方式分类
悲观锁:每次查询数据时都认为别人会修改,很悲观,所以查询时加锁。
乐观锁:每次查询数据时都认为别人不会修改,很乐观,但是更新时会判断-下在此期间别人有没有去更新这个数据。
InnoDB共享锁
采用带有索引的列进行加锁,加的是行锁,如果是不带索引的列,就会提升为一个表锁
共享锁和共享锁是兼容的
数据可以被多个事务查询,但是不能进行修改数据
InnoDB排他锁
普通查询没问题,只要是加锁查询就有问题了
排他锁和共享锁不兼容
排他锁和排他锁不兼容
MyISAM读锁
要想让修改操作成功,必须解锁,而不是上面两种只要commit就可以了
MyISAM读锁
要想其他连接操作成功,也是必须解锁
悲观锁和乐观锁
了解