MySQL存储过程和触发器

本文可以解决的问题

  1. 存储过程的作用是什么?

  2. 如何创建一个存储过程?

  3. MySQL中的变量都有哪几种?

  4. 如何定义一个变量?

  5. MySQL中使用变量是否需要提前声明?

  6. MySQL中的参数分为哪几种?

  7. 用过游标吗?游标的作用是什么?

  8. 了解条件处理程序吗?介绍一下如何使用

  9. 存储函数与存储过程的区别是什么?

  10. 如何查看数据库中创建的存储过程?

  11. 什么是触发器?

  12. MySQL中触发器分为几种类型?

  13. 行级触发器与语句级触器的区别是什么?

  14. 说一下了解的触发器使用场景都有哪些?

  15. 如果对一表中的数据进行更新,要在日志表中记录该条记录更新前与更新后的值,如何实现?

  16. 如何查看数据库中创建的触发器?

什么是存储过程

存储过程是一组为了完成特定功能的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均支持多个变量赋值,之间使用逗号隔开

sql 复制代码
select @e5 := 10, @e6 := 10;

2. 方法四仅支持单个变量,单条查询结果赋值,多条会报错

sql 复制代码
select c.name into @c1 from class c 
JOIN student s on s.class_id=c.id 
where s.id=1;

3. 方法3支持在查询动态赋值 ,属于赋值+查询

  1. 在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触发器 。使用oldnew关键字来引用触发器中发生变化的记录内容

insert触发器:new表示将要或已经新增的数据行

update触发器:old表示修改之前的数据,new表示将要或已经修改的数据

delete触发器:old表示将要或已经删除的数据

行级触发器和语句级触发器:

行级触发器(MYSQL支持):

当对表中的每一行 进行新增、修改、删除操作时,行级触发器会被触发,如果一个update 语句更新了多行数据,那么每一行都会触发一次。主要用于数据验证、复杂业务逻辑

语句级触发器(MYSQL不支持):

在整个语句中只触发一次。主要用于全局操作,如数据同步,数据清理

语法

新建触发器:

查看 / 删除触发器:

相关推荐
x***r1511 小时前
phpstudy_x64_8.1.1.3安装教程(含Apache/MySQL启动与端口修改)
数据库·mysql·apache
笨蛋不要掉眼泪1 小时前
Sentinel 流控规则详解:三种模式与三种效果实战指南
java·jvm·数据库·后端·sentinel
cjl_8520082 小时前
MySQL-递归查询
数据库·windows·mysql
一个响当当的名号2 小时前
lectrue15 并发控制理论
数据库
野犬寒鸦2 小时前
Java8 ConcurrentHashMap 深度解析(底层数据结构详解及方法执行流程)
java·开发语言·数据库·后端·学习·算法·哈希算法
tod1133 小时前
Redis 分布式锁进阶:从看门狗到 Redlock 的高可用实践
数据库·redis·分布式
山岚的运维笔记3 小时前
SQL Server笔记 -- 第69章:时态表
数据库·笔记·后端·sql·microsoft·sqlserver
一只理智恩3 小时前
向量数据库在AI领域的核心作用、优势与实践指南
数据库·人工智能
那个松鼠很眼熟w3 小时前
1.JDBC程序的一般步骤
数据库