本文可以解决的问题
存储过程的作用是什么?
如何创建一个存储过程?
MySQL中的变量都有哪几种?
如何定义一个变量?
MySQL中使用变量是否需要提前声明?
MySQL中的参数分为哪几种?
用过游标吗?游标的作用是什么?
了解条件处理程序吗?介绍一下如何使用
存储函数与存储过程的区别是什么?
如何查看数据库中创建的存储过程?
什么是触发器?
MySQL中触发器分为几种类型?
行级触发器与语句级触器的区别是什么?
说一下了解的触发器使用场景都有哪些?
如果对一表中的数据进行更新,要在日志表中记录该条记录更新前与更新后的值,如何实现?
如何查看数据库中创建的触发器?
什么是存储过程
存储过程是一组为了完成特定功能的SQL语句集 (一条或多条语句),经编译后存储在数据库中,用户通过指定存储过程的名字和参数 来执行,并获取相应的结果。可以理解为用SQL语言实现的方法
两种交互方式
应用与数据库的交互方式分为两种,一种是应用直接 操作表,另一种是应用通过存储过程操作表
应用直接操作表: 多个应用程序直接与数据库 建立连接,通过SQL语句直接读写数据。应用与数据表强绑定,每个应用都需要独立维护对表的访问逻辑。在应用程序中处理业务逻辑,可以帮助数据库分担压力,让数据库主要处理数据的存储和检索,从而提高性能

应用通过存储过程操作表: 所有应用程序仅与数据库中的存储过程 交互,由存储过程统一封装对表的CRUD逻辑。
特点:
**1.封装性:**将业务逻辑封装在数据库内部,减少应用程序的复杂性
**2.可维护性:**集中管理数据库操作,便于维护和更新
**3.可重用性:**封装了一个"查询用户订单列表"的存储过程逻辑,可以被用户中心,订单管理等多个应用系统重复调用

优点:
1. 性能优化: 存储过程在首次 执行时会编译并存储在数据库中,后续调用无需重复编译,执行效率高于单次发送SQL语句
2. 代码重用: 存储过程可重复调用,减少重复代码,提高代码的可维护性
**3. 安全性:**可以限制用户直接访问数据库,通过存储过程间接访问,从而保证系统安全性
4. 事务管理: 支持在存储过程内部实现包含多部操作的复杂事务逻辑,通过提交和回滚确保数据的一致性
5. 降低系统耦合: 当表结构发生变化时,只需修改相应的存储过程,应用程序的改动较小
缺点:
**1. 可移植性差:**不同数据库对SQL的实现方式有所差异,存储过程不能跨数据库移植
**2. 调试困难:**只有少数数据库管理系统支持存储过程的调试,开发和维护困难
**3. 不适合高并发场景:**在高并发场景下,存储过程可能会增加数据库的压力,难以维护
语法
创建/调用

注意:
1. 在命令行 中创建存储过程要使用delimiter 修改语句结束标 ,因为在存储过程中编写SQL语句时使用分号 ; 作为结束符时,会与SQL语句的分号冲突,导致提前提交整个存储过程的创建语句
2. 创建语句首次运行完成后会编译并存储到数据库中
3. 不可重复定义相同名字的存储过程
查看
查看指定数据库中创建的存储过程

查看存储过程的定义

删除

变量
MySQL中的变量可以分为三类:系统变量,用户自定义变量,局部变量
系统变量@@
系统变量是MySQL服务器的配置变量 ,控制着服务器的行为和性能 ,分为全局变量(GLOBAL) 和会话变量(SESSION)
全局变量: 作用于整个MySQL服务器实例,修改后对新建会话生效
会话变量:单个客户端会话,修改后仅对当前会话生效,不影响全局变量的值
查看系统变量

设置系统变量

注意:
1. 如果没有指定作用域,那么默认是session
2. MySQL 重启后,设置的全局变量失效 ,如果想使全局变量永久生效,就需要修改配置文件
用户自定义变量@
用户自定义变量是在SQL会话 中定义的变量,不用提前声明 ,作用域为当前会话,用来保存查询的中间结果,以便以后使用
赋值

注意:
1. 方法1,2,3均支持多个变量赋值,之间使用逗号隔开
sqlselect @e5 := 10, @e6 := 10;2. 方法四仅支持单个变量,单条查询结果赋值,多条会报错
sqlselect c.name into @c1 from class c JOIN student s on s.class_id=c.id where s.id=1;3. 方法3支持在查询 中动态赋值 ,属于赋值+查询
- 在SQL中比较相等也是使用等号,所以在变量赋值的时候,推荐使用 :=
使用
把用户自定义变量当成 c++/java中定义的变量使用就好,查询变量的值使用select语句

局部变量
局部变量只 在存储过程、函数或触发器 的范围内有效。需要使用declare 声明,作用域的范围在声明的begin ... end块内
声明
变量可以是任何 有效的MySQL数据类型

注意:
**1.**变量名不区分大小写,避免使用保留字作为变量名
2. 在存储过程和函数中,局部变量必须提前声明
**3.**在存储过程或函数结束时失效
赋值

使用
**例子:**在存储过程中定义局部变量记录学生表的总记录数
sql
delimiter //
create procedure p1()
BEGIN
declare c int default 0;
select count(*) into c from exam;
select c;
END//
delimiter ;
call p1();
SQL编程
SQL是结构化查询语言 的简称,是一种特殊目的的编程语言,是一种数据库查询和程序设计 语言,用于存取数据 以及查询、更新和管理关系型数据库系统
条件判断

参数
in(默认) :输入类型 ,调用存储过程时要存入的值,可以理解为值类型
out : 输出类型,没有初始值传入,单向返回
inout : 输入输出类型,既可以作为输入类型,也可作为输出类型,可以理解为引用类型
语法

举例
sql
delimiter //
create procedure p_check5(in score int,out result varchar(10))
BEGIN
if score >= 90 THEN
set result := '优秀';
elseif score >=80 THEN
set result := '良好';
elseif score >= 60 then
set result := '及格';
else
set result := '不及格';
end if;
END//
delimiter ;
call p_check5(60,@result);
select @result;
CASE
语法一
**1.**有匹配的值,则执行对应的语句
**2.**没有匹配的值,则执行else语句
**3.**既没有匹配的值也没有else语句,报错

语法二
可以理解为ifelse的简化写法

循环
while

repeat
类似于do-while循环,但是这里表示条件满足则退出循环

loop
loop也可以实现一个简单的循环,并且当满足某个条件时终止当前循环 或退出整个循环
**leave 循环名:**退出整个循环
**iterate 循环名:**终止当前循环

游标
MySQL中的游标是一种数据库对象 ,允许在存储过程 和函数 中对查询到的结果集进行逐行检索 。游标是只读的,不能进行更新操作
语法
使用游标之前必须先声明游标 ,之后使用open、fetch、close 语句来打开游标,获取游标记录和关闭游标。
游标必须在条件处理程序之前被声明,并且变量必须在游标或条件处理程序之前被声明

注意:
声明游标:定义 游标的名称 ,并关联 一个select查询语句,这一步仅完成定义,不会执行查询
打开游标:执行 关联的select查询 ,生成结果集并与游标绑定 (结果集固定 ,后续修改不会影响当前结果集)。此时游标处于激活状态 ,指向结果集的起始位置 (第一行之前)
获取游标记录: 将游标当前指向的记录行数据,赋值给提前定义的变量 (变量数量,类型需要与查询结果列完全对应)每执行 一次fetch,游标自动移动到下一行
关闭游标: 释放游标与结果集的关联 ,但游标定义仍保留,后续可绑定新的结果集
例子
sql
delimiter //
create procedure p_check04(in class_id bigint)
BEGIN
-- 定义变量
declare sname varchar(20);
declare cname varchar(30);
-- 声明游标
declare y1 cursor for select s.name s_name , c.name c_name from student s join class c on s.class_id=c.id
where class_id =c.id;
-- 打开游标
open y1;
-- 获取游标记录
while true DO
fetch y1 into sname,cname;
insert t_student_class values(null,sname,cname);
end while;
-- 关闭游标
close y1;
END//
delimiter ;
由于while的循环条件为TRUE ,是一个死循环,此时就会出现游标越界,可以通过条件处理程序解决
条件处理程序
用于保证存储过程或函数 在遇到警告或错误时能继续执行 ,避免程序异常停止运行
定义条件: 事先声明程序执行过程中可能遇到的特定问题(如错误码,SQLSTATE),相当于给异常命名,方便后续引用。
处理程序: 定义遇到上述问题时应当采取的具体处理方法

条件处理程序需要声明在存储过程 、函数变量 、 游标声明 之后,业务逻辑代码之前
MYSQL错误码参考网站:https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html
存储函数
存储函数是一个有返回值的存储过程,主要用于计算并返回一个值
有返回值: 必须通过returns子句 指定返回类型 ,并在函数体中使用return 语句返回一个值
参数类型: 参数类型只能是in ,定义存储函数时可以省略
类似内置函数: 存储函数的使用和MYSQL的内置函数类似,可以直接在select语句中调用

可以指定多个特性,使用逗号隔开,注意特性的互斥性
**例子:**传入一个数n,计算从1累加到n的值
sql
delimiter //
create function p_com01(n int)
returns int deterministic
BEGIN
declare ret int default 0;
while n > 0 DO
set ret = ret + n;
set n = n - 1;
end while;
return ret;
END//
delimiter ;
触发器
触发器是一个与表关联的数据库对象 ,在对表进行insert 、update、delete 操作时,触发并执行定义触发器时指定的SQL语句
概念
关联对象: 触发器是与表 紧密关联的数据库对象,不能独立存在
触发时间: 在对表进行修改操作之前或之后执行
**执行逻辑:**执行预定义的SQL语句或逻辑块,常用于实现数据验证,日志记录等自动化任务
MYSQL支持三种触发器:insert触发器、update触发器、delete触发器 。使用old 和new关键字来引用触发器中发生变化的记录内容
insert触发器:new表示将要或已经新增的数据行
update触发器:old表示修改之前的数据,new表示将要或已经修改的数据
delete触发器:old表示将要或已经删除的数据
行级触发器和语句级触发器:
行级触发器(MYSQL支持):
当对表中的每一行 进行新增、修改、删除操作时,行级触发器会被触发,如果一个update 语句更新了多行数据,那么每一行都会触发一次。主要用于数据验证、复杂业务逻辑
语句级触发器(MYSQL不支持):
在整个语句中只触发一次。主要用于全局操作,如数据同步,数据清理
语法
新建触发器:

查看 / 删除触发器:
