或許你曾經去面試的時候被問到過關於mysql數據庫的存儲過程和觸發器的問題,若是你還不懂能夠看下這篇關於存儲過程和觸發器的文章,但願能幫助到有須要的朋友。javascript

Mysql存儲過程與觸發器java
本篇文章主要是簡單解釋mysql中存儲過程的建立、調用以及介紹觸發器和如何建立觸發器。那麼關於存儲過程和觸發器那些官方理論的介紹我就不在這裏囉嗦了。mysql
1數據表的準備面試
下面全部例子中用到的表的建立腳本。tb_user是下面例子中的用戶表,tb_blog是博客表,tb_user_log是用戶信息更新日記表。sql
- use db_mybatis;
-
- create table tb_user(
- id int(11) unsigned not null auto_increment,
- uname varchar(50) not null,
- pwd varchar(50) not null,
- primary key (id)
- )engine=InnoDB default charset=utf8;
-
-
- create table tb_blog(
- id int(11) unsigned not null auto_increment,
- title varchar(50) not null,
- details varchar(50) not null,
- create_date datetime not null,
- update_date datetime not null,
- primary key (id)
- )engine=InnoDB default charset=utf8;
-
- create table tb_user_log(
- id int(11) unsigned not null auto_increment,
- create_date datetime not null,
- details varchar(255) not null,
- primary key (id)
- )engine=InnoDB default charset=utf8;
2「delimiter //」的解釋數據庫
mysql默認以';'做爲語句結束符。咱們都知道,在mysql命令行模式下,當輸入一條語句時,若是不加‘;’回車是不會執行輸入的sql語句的。如:mybatis
- mysql> select * from tb_blog
- ->
- ->
- ->
- ->
- -> ;
- +----+--------+--------------+---------------------+---------------------+
- | id | title | details | create_date | update_date |
- +----+--------+--------------+---------------------+---------------------+
- | 2 | dsssss | 這是內容 | 2018-08-13 02:42:44 | 2018-08-15 16:39:16 |
- | 3 | new1 | 這是內容 | 2018-08-13 02:42:44 | 2018-08-13 22:04:21 |
- | 4 | new2 | 這是內容 | 2018-08-13 02:42:44 | 2018-08-13 22:04:21 |
- | 5 | new3 | 這是內容 | 2018-08-13 02:42:44 | 2018-08-13 22:04:21 |
- | 6 | new4 | 這是內容 | 2018-08-13 02:42:44 | 2018-08-13 22:04:21 |
- +----+--------+--------------+---------------------+---------------------+
- 5 rows in set (0.01 sec)
而delimiter的做用就是修改語句結束符,如delimiter &就是將sql語句的結束爲定義爲'&'符號,當遇到'&'符號時,mysql判斷爲語句輸入完成就會執行,看下面例子:函數
- mysql> delimiter &
- mysql> select * from tb_blog
- ->
- -> &
- +----+--------+--------------+---------------------+---------------------+
- | id | title | details | create_date | update_date |
- +----+--------+--------------+---------------------+---------------------+
- | 2 | dsssss | 這是內容 | 2018-08-13 02:42:44 | 2018-08-15 16:42:54 |
- | 3 | new1 | 這是內容 | 2018-08-13 02:42:44 | 2018-08-13 22:04:21 |
- | 4 | new2 | 這是內容 | 2018-08-13 02:42:44 | 2018-08-13 22:04:21 |
- | 5 | new3 | 這是內容 | 2018-08-13 02:42:44 | 2018-08-13 22:04:21 |
- | 6 | new4 | 這是內容 | 2018-08-13 02:42:44 | 2018-08-13 22:04:21 |
- +----+--------+--------------+---------------------+---------------------+
- 5 rows in set (0.00 sec)
因此,delimiter //的做用是將'//'做爲語句的結束符,'//'能夠是其餘的字符,好比上面例子中使用'&';命令行
那麼爲何編寫存儲過程和觸發器咱們須要將默認的';'修改成'//'做爲sql語句結束符呢?由於咱們要在存儲過程或觸發器中執行sql語句,因此會用到';',若是不改其它符號而使用';'做爲語句結束符的話,mysql遇到';'就看成一條語句完成了,而存儲過程或觸發器的sql語句都沒寫徹底呢,這樣只會ERROR。blog
注意,在使用delimiter //將sql語句結束符改成'//'用完後(如完成建立存儲過程)記得要使用delimiter ;將sql語句結束符改回爲默認。
3存儲過程
先來看兩個簡單的存儲過程實例,對存儲過程的建立和調用有一個模糊的印象。
- #實例一:建立查詢全部博客的存儲過程
- drop procedure if exists select_procedure
- delimiter //
- create procedure select_procedure()
- begin
- select * from tb_blog;
- end //
- delimiter ;
- #調用
- call select_procedure;
-
-
- #實例二:更新博客修改時間的存儲過程
- drop procedure if exists update_blog_updatedate;
- delimiter //
- create procedure update_blog_updatedate(blogid int(11))
- begin
- update tb_blog set update_date = sysdate() where id = blogid;#sysdate()獲取當前日期+時間字符串(24小時格式)
- end //
- delimiter ;
- #調用
- call update_blog_updatedate(2);
好,下面我經過一個簡單的存儲過程實例來分析如何建立一個存儲過程。先看例子:
- #建立更新博客標題的存儲過程
- drop procedure if exists update_blog;#若是存在該存儲過程先刪除
- delimiter //
- create procedure update_blog(blogid int(11))
- begin
- start transaction;#開啓事務
- update tb_blog set title='dsssss' where id=blogid;#要作的事情
- commit;#提交事務
- end //
- delimiter ;
上面實際建立存儲過程的語句爲
- create procedure update_blog(blogid int(11))#(參數1 參數類型(長度),參數2 參數類型(長度),...)
- begin
- start transaction;#開啓事務
- update tb_blog set title='dsssss' where id=blogid;#要作的事情
- commit;#提交事務
- end //
end後面的'//'是sql語句結束符,就是前面用delimiter //修改的sql語句結束符,因此從create到//就是一條完整的建立存儲過程的sql語句。那麼爲何還要在前面加一條drop procedure if exists update_blog?其實你能夠不加的,這條語句的做用只是當要建立的存儲過程已經存在同名的存儲過程時將已經存在的存儲過程刪除。
如今再來解析建立存儲過程的這條語句,其中,update_blog時存儲過程的名稱,()內是調用該存儲過程時要傳遞的參數,參數個數不限制,參數間用','分割,參數要聲明類型,如blogid int(11),blogid就是參數名,int是類型,若是要指定長度則在類型後面加'(長度)'。
begin和end之間就是存儲過程要作的事情。
使用call+存儲過程名稱來調用存儲過程,若是存儲過程定義了參數,那麼須要在調用的時候傳入參數,不然調用失敗。
- call update_blog(2);#調用存儲過程
下面來看一個稍微成型點的存儲過程。
- # 建立批量更新的存儲過程
- drop procedure if exists update_all_blog_date;
- delimiter //
- create procedure update_all_blog_date()
- begin
- declare id_index int(11) default 0;#定義變量id_index,類型爲int,默認值爲0
- declare blog_count int default 0;
- declare bid int;
- select count(*) into blog_count from tb_blog;#into blog_count 將查詢結果賦值給blog_count變量
- if blog_count>0 then
- #start transaction;
- while id_index<=blog_count do
- #update tb_blog set update_date = sysdate() where id in
- #(select tb.id from (select id from tb_blog limit id_index,1) as tb);
- #set id_index=id_index+1;
-
- select id into bid from tb_blog limit id_index,1;
- update tb_blog set update_date = sysdate() where id = bid;
- set id_index=id_index+1;
- end while;
- #commit;
- end if;
- end //
- delimiter ;
-
- call update_all_blog_date;
解析:
declare是定義變量的關鍵字,能夠理解爲javascript中的var關鍵字。定義變量必須是在存儲過程的內部,即begin和end之間。變量的定義方式是declare關鍵字加變量名加變量類型,若是想指定默認值就在類型後面加上「default 默認值」。
select count(*) into blog_count from tb_blog語句是獲取tb_blog表的總數賦值給blog_count,將查詢結果賦值給某個變量使用into關鍵字。
set關鍵字是修改變量的值,將一個新的值寫給set指定的變量。其它的就不作解釋了,看不懂就須要學一下mysql的條件語句與循環語句了。
4Mysql中的觸發器
觸發器是什麼?
觸發器就是一個函數,當知足某種條件時纔會觸發其執行。
什麼狀況下使用觸發器?
好比咱們要爲用戶所作的我的信息修改記錄一條變動日記,那麼是否是須要在修改完用戶信息以後添加一條日記記錄?若是不使用觸發器咱們就須要執行兩條sql語句,第一條是修改用戶信息的sql語句,第二條是添加一個日記記錄的sql語句。咱們在寫業務邏輯代碼的時候若是在多處地方可能對用戶信息修改,在某處忘記了寫日記記錄也不奇怪。而若是使用觸發器,當用戶信息修改時觸發觸發器執行添加一條日記記錄,這樣也會比在業務代碼中執行兩條sql語句效率要高。
那麼若是建立一個觸發器呢?
- create trigger 觸發器名稱 after|before insert|delete|update on 表名 for each row
- begin
- #觸發器要作的事情
- end
- 表名:將改觸發器的觸發條件掛載在哪張表上,也就是指定哪張表的操做知足條件時觸發該觸發器。
- 觸發器執行時機:after或者before,即以前仍是以後。
- 觸發的條件:insert|delete|update 便可選增刪改時觸發;好比alter insert,就是在添加完成以後觸發,執行時機與觸發條件可隨意組合使用,即
before insert
before delete
before update
after insert
after delete
after update
- for each row表示任何一條記錄的操做知足觸發條件都會觸發觸發器執行。
下面來看一個實例:在用戶信息表tb_user中的記錄被修改以後添加一條日記記錄,記錄修改時間和修改內容。
- drop trigger if exists on_user_info_chang_log;
- delimiter //
- create trigger on_user_info_chang_log after update on tb_user for each row
- begin
- declare info varchar(255) charset utf8 default '';
- set info = '修改以前的信息爲:[';
- set info = concat(info,NEW.uname);
- set info = concat(info,',');
- set info = concat(info,New.pwd);
- set info = concat(info,'],修改以前的信息爲:[');
- set info = concat(info,OLD.uname);
- set info = concat(info,',');
- set info = concat(info,OLD.pwd);
-
- insert into tb_user_log (create_date,details) value(sysdate(),info);
- end //
- delimiter ;
解析:
- concat函數是字符串拼接函數
- NEW是修改後的新的記錄
- OLD是修改前的舊的紀錄
- sysdate函數是獲取當前系統日期時間字符串
下面咱們執行一條sql來觸發該觸發器
- update tb_user set uname='new_name' where id = 1;
查看日記表中是否添加了一條記錄。
