MySQL存儲(chǔ)過程、游標(biāo)與觸發(fā)器示例詳解
1.存儲(chǔ)過程
概念:存儲(chǔ)過程是一組預(yù)編譯的SQL語句集合,存儲(chǔ)在數(shù)據(jù)庫中,可通過名稱調(diào)用。支持條件判斷、循環(huán)等邏輯控制,適合封裝復(fù)雜業(yè)務(wù)邏輯


優(yōu)勢:- 性能優(yōu)化:存儲(chǔ)過程在創(chuàng)建時(shí)已經(jīng)經(jīng)過編譯和優(yōu)化,形成可執(zhí)行的二進(jìn)制代碼,直接存儲(chǔ)在數(shù)據(jù)庫服務(wù)器中。性能高于單獨(dú)執(zhí)行時(shí)需要解析、編譯的SQL語句
- 代碼復(fù)用:存儲(chǔ)過程可以重復(fù)調(diào)用(類似C語言函數(shù)/Java方法)
- 安全性高:避免應(yīng)用程序直接訪問數(shù)據(jù)庫,通過存儲(chǔ)過程間接訪問(結(jié)合參數(shù)化查詢),從而保證安全性
- 降低耦合:當(dāng)表結(jié)構(gòu)發(fā)生變化時(shí),只需要修改相應(yīng)的存儲(chǔ)過程,應(yīng)用程序變動(dòng)較小
缺點(diǎn):- 移植性差:不同數(shù)據(jù)庫創(chuàng)建存儲(chǔ)過程的語法不同
- 不適合高并發(fā)場景:高并發(fā)場景下,存儲(chǔ)過程會(huì)進(jìn)一步降低數(shù)據(jù)庫的性能
語法:
-- 修改SQL語句結(jié)束符為//
delimiter //
-- 創(chuàng)建存儲(chǔ)過程
create procedure if not exists 存儲(chǔ)過程名(參數(shù)列表)
begin
-- SQL語句
end//
-- 還原SQL語句結(jié)束符為;
delimiter ;
-- 調(diào)用存儲(chǔ)過程
call 存儲(chǔ)過程名(參數(shù)列表);
-- 刪除存儲(chǔ)過程
drop procedure if exists 存儲(chǔ)過程名;
-- 查看當(dāng)前數(shù)據(jù)庫已創(chuàng)建的存儲(chǔ)過程
select * from information_schema.routines where routine_schema = 數(shù)據(jù)庫名;在MySQL中,存儲(chǔ)過程、函數(shù)等數(shù)據(jù)庫對象的信息可以通過information_schema(數(shù)據(jù)庫)中的routines(數(shù)據(jù)表)系統(tǒng)視圖查詢。這個(gè)視圖包含所有數(shù)據(jù)庫中的存儲(chǔ)過程和函數(shù)的元數(shù)據(jù)信息
- routine_schema:所屬的數(shù)據(jù)庫名
- routine_name:存儲(chǔ)過程/函數(shù)名稱
- routine_type:對象類型(procedure或function)
- data_type:函數(shù)返回值類型,存儲(chǔ)過程沒有返回值
- routine_definition:存儲(chǔ)過程/函數(shù)的定義語句
2.變量
2.1 系統(tǒng)變量
系統(tǒng)變量分為全局變量和會(huì)話變量
全局變量:影響整個(gè)服務(wù)器運(yùn)行環(huán)境,MySQL服務(wù)器啟動(dòng)時(shí)從my.ini文件(默認(rèn)文件路徑如下)讀取初始值

- 會(huì)話變量:僅影響當(dāng)前會(huì)話連接,每個(gè)客戶端連接可以有自己的會(huì)話變量設(shè)置(默認(rèn)從全局變量繼承其初始值)
-- 查詢?nèi)?會(huì)話變量 show [global|session] variables [like...]; select @@[global|session].系統(tǒng)變量名; -- 修改全局/會(huì)話變量 set [global|session] 系統(tǒng)變量名 = 值; set @@[global|session].系統(tǒng)變量名 = 值;
- 未指定
[global|session]時(shí)默認(rèn)查詢/修改session變量 - 上述修改操作僅為內(nèi)存級修改,MySQL服務(wù)器啟動(dòng)時(shí)從my.ini文件讀取初始值
2.2 用戶變量
用戶變量以
@符號(hào)開頭,作用域?yàn)楫?dāng)前會(huì)話連接,不需要提前聲明。常在存儲(chǔ)過程中作為參數(shù)傳遞,用于存儲(chǔ)查詢中間結(jié)果
-- 設(shè)置用戶變量 set @user_demo = 值; -- 查詢用戶變量 select @user_demo; -- 設(shè)置并查詢用戶變量 select @user_demo := 值;
2.3 局部變量
局部變量僅存在于存儲(chǔ)過程、函數(shù)、觸發(fā)器中,使用
declare聲明
delimiter // create procedure if not exists query() begin declare num int default 0; set num := 100; select num; end// delimiter ; call query();
3.SQL編程
3.1 參數(shù)列表/if
| 類型 | 描述 |
|---|---|
| in | 輸入型參數(shù),調(diào)用存儲(chǔ)過程時(shí)傳入,默認(rèn)參數(shù)類型 |
| out | 輸出型參數(shù),可以作為存儲(chǔ)過程的返回值 |
| inout | 輸入輸出型參數(shù) |
if語法:
if 條件1 then -- sql語句1 elseif then --sql語句2 else -- sql語句3 end if;
示例:
-- 示例1
delimiter //
create procedure demo_if(in score int,out result varchar(20))
begin
if score >= 90 then
set result := '優(yōu)秀';
elseif score >= 80 and score < 90 then
set result = '良好';
elseif score >= 70 and score < 80 then
set result = '及格';
else
set result = '不及格';
end if;
end//
delimiter ;
call demo_if(60,@result);
select @result;
-- 示例2
set @score := 70;
delimiter //
create procedure demo2_if(inout score int)
begin
set score := score + 10;
end//
delimiter ;
call demo_if_2(@score);
select @score;
3.2 case
語法:
-- 簡單case表達(dá)式:將一個(gè)表達(dá)式與一組簡單值進(jìn)行比較
case case_value
when when_value1 then result1
when when_value2 then result2
...
else else_result
end
-- 搜索case表達(dá)式:將一個(gè)表達(dá)式與一組獨(dú)立的布爾表達(dá)式進(jìn)行比較
case
when condition1 then result1
when condition2 then result2
...
else else_result
end
示例:
-- 示例1
delimiter //
create procedure demo_case(in code int,out result varchar(50))
begin
case code
when 0 then
set result := '成功';
when 10001 then
set result := '用戶名或密碼錯(cuò)誤';
when 10002 then
set result := '沒有權(quán)限';
when 20001 then
set result := '傳入?yún)?shù)有誤';
when 20002 then
set result := '無結(jié)果';
else
set result := '內(nèi)部錯(cuò)誤';
end case;
end//
delimiter ;
call demo_case(10002,@result);
select @result;
-- 示例2
delimiter //
create procedure demo2_case(in month int,out result varchar(50))
begin
case
when month >=1 and month <= 3 then
set result = '第一節(jié)度';
when month >=4 and month <= 6 then
set result = '第二節(jié)度';
when month >=7 and month <= 9 then
set result = '第三節(jié)度';
when month >=10 and month <= 12 then
set result = '第四節(jié)度';
else
set result = '非法輸入';
end case;
end//
delimiter ;
call demo2_case(7,@result);
select @result;
3.3 while
語法:
-- search_condition:循環(huán)條件表達(dá)式 -- statement_list:循環(huán)體內(nèi)要執(zhí)行的SQL語句 while search_condition do statement_list end while;
示例:
delimiter //
create procedure demo_while(in n int)
begin
declare sum int default 0;
while n > 0 do
set sum := sum + n;
set n := n - 1;
end while;
select sum;
end//
delimiter ;
call demo_while(100);
3.4 repeat
先執(zhí)行一次
statement_list,再判斷search_condition是否成立
語法:
repeat statement_list until search_condition end repeat;
示例:
delimiter //
create procedure demo_repeat(in n int)
begin
declare sum int default 0;
repeat
set sum := sum + n;
set n := n - 1;
until n <= 0 end repeat;
select sum;
end//
delimiter ;
call demo_repeat(100);
3.5 loop
語法:
-- loop_label:標(biāo)記loop的標(biāo)簽 loop_label:loop statement_list end loop loop_label;
控制loop循環(huán)的關(guān)鍵字:
- leave:用于退出循環(huán),相當(dāng)于其他語言中的break
- iterate:用于跳過當(dāng)前迭代,繼續(xù)下一次循環(huán),相當(dāng)于其他語言中的continue
示例:
-- 求1-100所有偶數(shù)的和
delimiter //
create procedure demo_loop(in n int)
begin
declare total int default 0;
sum: loop
if n <= 0 then
leave sum;
end if;
if n % 2 = 1 then
set n := n - 1;
iterate sum;
end if;
set total := total + n;
set n := n - 1;
end loop sum;
select total;
end//
delimiter ;
call demo_loop(100);
3.6 游標(biāo)&條件處理程序
3.6.1 游標(biāo)
游標(biāo)(cursor):是一種數(shù)據(jù)庫對象,用于在存儲(chǔ)過程或函數(shù)中逐行處理查詢結(jié)果集。當(dāng)游標(biāo)遍歷到結(jié)果集末尾時(shí),會(huì)觸發(fā)not found狀態(tài),需要結(jié)合條件處理程序結(jié)束循環(huán),避免無限執(zhí)行
語法:
-- 聲明游標(biāo) declare cursor_name cursor for 查詢語句 -- 打開游標(biāo) open cursor_name; -- 獲取游標(biāo)記錄 fetch cursor_name into
3.6.2 條件處理程序
條件處理程序:用于捕獲和處理SQL執(zhí)行過程中的異常或特定狀態(tài),需與游標(biāo)配合使用
語法:
declare handler_type handler for condition statement; -- 1.handler_type:條件處理程序類型 (1) continue -- 繼續(xù)執(zhí)行后續(xù)語句 (2) exit -- 終止當(dāng)前begin...end塊 -- 2.condition:指定了處理程序會(huì)響應(yīng)的條件類型 (1) mysql_error_code -- MySQL錯(cuò)誤碼 (2) sqlstate sqlstate_value -- 表示特定的SQL狀態(tài)碼 (3) not found -- 捕獲所有以'02'開頭的sqlstate代碼 (4) sqlwarning -- 捕獲所有以'01'開頭的sqlstate代碼的警告 (5)sqlexception -- 捕獲所有不以'00'(成功)、'01'(警告)、'02'(未找到)開頭的sqlstate代碼的錯(cuò)誤 -- 3.statement:SQL語句
3.6.3 示例
初始化數(shù)據(jù):
-- 創(chuàng)建班級表
create table class (id int primary key);
-- 創(chuàng)建學(xué)生表
create table student(id int primary key auto_increment,name varchar(20),sno varchar(10),age int,gender tinyint default 1,enroll_date datetime default now(),class_id int,foreign key (class_id) references class(id));
-- 向班級表插入數(shù)據(jù)
insert into class values (1),(2);
-- 向?qū)W生表插入數(shù)據(jù)
insert into student (name,sno,age,class_id) values ('劉備','100001',18,1),('關(guān)羽','100002',18,1),('張飛','100003',18,2),('趙云','100004',18,2);
示例:
delimiter //
create procedure demo_cursor(in input_class_id int)
begin
-- 聲明變量用于接收每一列的結(jié)果
declare student_name varchar(20);
declare class_id int;
declare flg bool default true;
-- 聲明游標(biāo)用于接收查詢結(jié)果
declare demo_cursor cursor for
select s.name as student_name,c.id as id
from student as s,class as c
where s.class_id = c.id and s.class_id = input_class_id;
-- 聲明處理程序
declare continue handler for not found set flg := false;
-- 創(chuàng)建新表
create table class_new (id int primary key auto_increment,student_name varchar(20),class_id int,foreign key (class_id) references class(id)
);
-- 開啟游標(biāo)
open demo_cursor;
loop_read: loop
fetch demo_cursor into student_name,class_id;
if not flg then
leave loop_read;
end if;
insert into class_new values(null,student_name,class_id);
end loop loop_read;
-- 關(guān)閉游標(biāo)
close demo_cursor;
end//
delimiter ;
call demo_cursor(1);
運(yùn)行結(jié)果:
mysql> select * from class_new; +----+--------------+----------+ | id | student_name | class_id | +----+--------------+----------+ | 1 | 劉備 | 1 | | 2 | 關(guān)羽 | 1 | +----+--------------+----------+
3.7 存儲(chǔ)函數(shù)
存儲(chǔ)函數(shù):是一種存儲(chǔ)在數(shù)據(jù)庫中的可重用代碼塊,接收參數(shù)并返回一個(gè)值。與存儲(chǔ)過程不同,存儲(chǔ)函數(shù)必須包含返回值,且可以使用select直接調(diào)用
語法:
create function 存儲(chǔ)函數(shù)名 (參數(shù)列表) returns 返回值類型 [characteristic]
characteristic:可選特性- deterministic:表明函數(shù)對于相同的輸入?yún)?shù)總是返回相同的結(jié)果
- not deterministic:默認(rèn)選項(xiàng),表示函數(shù)可能對相同的輸入返回不同的結(jié)果
- no sql:表示函數(shù)不包含任何SQL語句
- reads sql data:表示函數(shù)包含讀取數(shù)據(jù)的SQL語句(select)
- modifies sql data:表示函數(shù)包含修改數(shù)據(jù)的SQL語句(insert/update/delete)
- contains sql:表示函數(shù)僅包含讀取數(shù)據(jù)的SQL語句,不修改數(shù)據(jù)
示例:
create function func1(n int) returns int deterministic
begin
declare `time` int default 0;
while n > 0 do
set `time` := `time` + n;
set n := n - 1;
end while;
return `time`;
end;
select func1(100);
4.觸發(fā)器
觸發(fā)器:一種與表相關(guān)的數(shù)據(jù)庫對象,在指定事件(如insert、update、delete)發(fā)生時(shí)自動(dòng)執(zhí)行預(yù)定義的SQL語句
觸發(fā)器類型:
1.從觸發(fā)時(shí)機(jī)區(qū)分
- before觸發(fā)器:在觸發(fā)事件執(zhí)行前激活
- after觸發(fā)器:在觸發(fā)事件完成后再執(zhí)行
2.從觸發(fā)事件區(qū)分
- insert觸發(fā)器:響應(yīng)數(shù)據(jù)插入操作
- update觸發(fā)器:響應(yīng)數(shù)據(jù)更新操作
- delete觸發(fā)器:響應(yīng)數(shù)據(jù)刪除操作
3.從作用粒度區(qū)分
- 行級觸發(fā)器:針對受影響的每一行數(shù)據(jù)都會(huì)觸發(fā)一次
- 語句級觸發(fā)器:整個(gè)SQL語句執(zhí)行完畢后僅觸發(fā)一次(MySQL暫不支持)
觸發(fā)器中的new和old
- new:表示觸發(fā)事件中的新數(shù)據(jù)
- old:表示觸發(fā)事件前的舊數(shù)據(jù)
語法:
create trigger 觸發(fā)器名
{before|after} {insert|update|delete} on 表名
for each row
begin
-- 觸發(fā)器邏輯
end;
初始化數(shù)據(jù):
-- 創(chuàng)建日志表 create table log (id int primary key auto_increment,operation_type varchar(20) not null comment '操作類型',operation_time datetime not null comment '操作時(shí)間', operation_id int not null comment '操作的記錄的id',operation_date varchar(500) comment '操作數(shù)據(jù)' );
4.1 insert觸發(fā)器
-- insert觸發(fā)器 create trigger trg_insert after insert on student for each row begin insert into log values (null,'insert',now(),new.id,concat(new.id,',',new.name,',',new.sno,',',new.age,',',new.gender,',',new.enroll_date,',',new.class_id)); end; -- 向?qū)W生表插入數(shù)據(jù) insert into student values (null,'馬超',200001,18,1,now(),1);
執(zhí)行結(jié)果:
mysql> select * from log; +----+----------------+---------------------+--------------+------------------------------------------+ | id | operation_type | operation_time | operation_id | operation_date | +----+----------------+---------------------+--------------+------------------------------------------+ | 1 | insert | 2025-10-31 17:25:17 | 9 | 9,馬超,200001,18,1,2025-10-31 17:25:17,1 | +----+----------------+---------------------+--------------+------------------------------------------+
4.2 update觸發(fā)器
-- update觸發(fā)器
create trigger trg_update after update on student for each row
begin
insert into log values (null,'update',now(),new.id,concat(' 更新前數(shù)據(jù): ',old.id,',',old.name,',',old.sno,',',old.age,',',old.gender,',',old.enroll_date,',',old.class_id,' ,更新后數(shù)據(jù): ',new.id,',',new.name,',',new.sno,',',new.age,',',new.gender,',',new.enroll_date,',',new.class_id));
end;
-- 更新學(xué)生表的數(shù)據(jù)
update student set age = 20,enroll_date = now(),class_id = 2 where name = '馬超';
執(zhí)行結(jié)果:
mysql> select * from log; +----+----------------+---------------------+--------------+---------------------------------------------------------------------------------------------------------------+ | id | operation_type | operation_time | operation_id | operation_date | +----+----------------+---------------------+--------------+---------------------------------------------------------------------------------------------------------------+ | 3 | insert | 2025-10-31 17:40:14 | 10 | 10,馬超,200001,18,1,2025-10-31 17:40:14,1 | | 4 | update | 2025-10-31 17:41:11 | 10 | 更新前數(shù)據(jù): 10,馬超,200001,18,1,2025-10-31 17:40:14,1 ,更新后數(shù)據(jù): 10,馬超,200001,20,1,2025-10-31 17:41:11,2 | +----+----------------+---------------------+--------------+---------------------------------------------------------------------------------------------------------------+
4.1 delete觸發(fā)器
-- delete觸發(fā)器
create trigger trg_delete after delete on student for each row
begin
insert into log values (null,'delete',now(),old.id,concat('刪除的數(shù)據(jù): ',old.id,',',old.name,',',old.sno,',',old.age,',',old.gender,',',old.enroll_date,',',old.class_id));
end;
delete from student where name = '馬超';
執(zhí)行結(jié)果:
mysql> select * from student; +----+------+--------+------+--------+---------------------+----------+ | id | name | sno | age | gender | enroll_date | class_id | +----+------+--------+------+--------+---------------------+----------+ | 1 | 劉備 | 100001 | 18 | 1 | 2025-10-26 22:11:23 | 1 | | 2 | 關(guān)羽 | 100002 | 18 | 1 | 2025-10-26 22:11:23 | 1 | | 3 | 張飛 | 100003 | 18 | 1 | 2025-10-26 22:11:23 | 2 | | 4 | 趙云 | 100004 | 18 | 1 | 2025-10-26 22:11:23 | 2 | +----+------+--------+------+--------+---------------------+----------+ 4 rows in set (0.00 sec) mysql> select * from log; +----+----------------+---------------------+--------------+---------------------------------------------------------------------------------------------------------------+ | id | operation_type | operation_time | operation_id | operation_date | +----+----------------+---------------------+--------------+---------------------------------------------------------------------------------------------------------------+ | 3 | insert | 2025-10-31 17:40:14 | 10 | 10,馬超,200001,18,1,2025-10-31 17:40:14,1 | | 4 | update | 2025-10-31 17:41:11 | 10 | 更新前數(shù)據(jù): 10,馬超,200001,18,1,2025-10-31 17:40:14,1 ,更新后數(shù)據(jù): 10,馬超,200001,20,1,2025-10-31 17:41:11,2 | | 5 | delete | 2025-10-31 17:47:09 | 10 | 刪除的數(shù)據(jù): 10,馬超,200001,20,1,2025-10-31 17:41:11,2 | +----+----------------+---------------------+--------------+---------------------------------------------------------------------------------------------------------------+
到此這篇關(guān)于MySQL存儲(chǔ)過程、游標(biāo)與觸發(fā)器的文章就介紹到這了,更多相關(guān)mysql存儲(chǔ)過程、游標(biāo)與觸發(fā)器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- mysql存儲(chǔ)過程游標(biāo)之loop循環(huán)解讀
- mysql存儲(chǔ)過程多層游標(biāo)循環(huán)嵌套的寫法分享
- mysql數(shù)據(jù)庫存儲(chǔ)過程之游標(biāo)(光標(biāo)cursor)詳解
- MySql存儲(chǔ)過程和游標(biāo)的使用實(shí)例
- mysql存儲(chǔ)過程之游標(biāo)(DECLARE)原理與用法詳解
- mysql的存儲(chǔ)過程、游標(biāo) 、事務(wù)實(shí)例詳解
- mysql存儲(chǔ)過程 游標(biāo) 循環(huán)使用介紹
- MySQL數(shù)據(jù)庫實(shí)驗(yàn)之?觸發(fā)器和存儲(chǔ)過程
- MySQL存儲(chǔ)過程中的基本函數(shù)和觸發(fā)器的相關(guān)學(xué)習(xí)教程
相關(guān)文章
CentOs7安裝部署Sonar環(huán)境的詳細(xì)過程(JDK1.8+MySql5.7+sonarqube7.8)
這篇文章主要介紹了CentOs7安裝部署Sonar環(huán)境(JDK1.8+MySql5.7+sonarqube7.8),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06
MySQL中JSON_ARRAYAGG和JSON_OBJECT函數(shù)功能和用法
JSON(JavaScript Object Notation)是一種輕量級的數(shù)據(jù)交換格式,它可以用來存儲(chǔ)和表示結(jié)構(gòu)化的數(shù)據(jù),在MySQL數(shù)據(jù)庫中,JSON格式的數(shù)據(jù)處理已經(jīng)變得越來越常見,本文將深入探討這兩個(gè)函數(shù)的用途、語法和示例,以幫助您更好地理解它們的功能和用法,需要的朋友可以參考下2023-09-09
阿里云Linux CentOS 7.2下自建MySQL的root密碼忘記的解決方法
這篇文章主要介紹了阿里云Linux CentOS 7.2下自建MySQL的root密碼忘記的解決方法,需要的朋友可以參考下2017-07-07
Navicat中導(dǎo)入mysql大數(shù)據(jù)時(shí)出錯(cuò)解決方法
這篇文章主要介紹了Navicat中導(dǎo)入mysql大數(shù)據(jù)時(shí)出錯(cuò)解決方法,需要的朋友可以參考下2017-04-04
安裝mysql 8.0.17并配置遠(yuǎn)程訪問的方法
這篇文章主要介紹了安裝mysql 8.0.17并配置遠(yuǎn)程訪問的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10

