MYSQL--儲存過程-觸發器-事務
本文內容:
儲存過程
觸發器
事務
一、儲存過程
什麼是儲存過程
大多數SQL語句都是針對一個或多個表的單條語句。並非所有的操作都怎麼簡單。經常會有一個完整的操作需要多條才能完成。儲存過程(Stored Procedure)是在大型資料庫系統中,一組為了完成特定功能的SQL 語句集,儲存在資料庫中經過第一次編譯後再次呼叫不需要再次編譯,使用者通過指定儲存過程的名字並給出引數(如果該儲存過程帶有引數)來執行它。儲存過程是資料庫中的一個重要物件,任何一個設計良好的資料庫應用程式都應該用到儲存過程。
為什麼要使用儲存過程
(1).儲存過程增強了SQL語言的功能和靈活性。儲存過程可以用流控制語句編寫,有很強的靈活性,可以完成複雜的判斷和較複雜的運算
(2).儲存過程允許標準組件是程式設計。儲存過程被建立後,可以在程式中被多次呼叫,而不必重新編寫該儲存過程的SQL語句。而且資料庫專業人員可以隨時對儲存過程進行修改,對應用程式原始碼毫無影響。
(3).儲存過程能實現較快的執行速度。如果某一操作包含大量的Transaction-SQL程式碼或分別被多次執行,那麼儲存過程要比批處理的執行速度快很多。因為儲存過程是預編譯的。在首次執行一個儲存過程時查詢,優化器對其進行分析優化,並且給出最終被儲存在系統表中的執行計劃。而批處理的Transaction-SQL語句在每次執行時都要進行編譯和優化,速度相對要慢一些。
(4).儲存過程能過減少網路流量。針對同一個資料庫物件的操作(如查詢、修改),如果這一操作所涉及的Transaction-SQL語句被組織程儲存過程,那麼當在客戶計算機上呼叫該儲存過程時,網路中傳送的只是該呼叫語句,從而大大增加了網路流量並降低了網路負載。
(5).儲存過程可被作為一種安全機制來充分利用。系統管理員通過執行某一儲存過程的許可權進行限制,能夠實現對相應的資料的訪問許可權的限制,避免了非授權使用者對資料的訪問,保證了資料的安全。
為什麼不使用儲存過程:
1)可移植性差
2)對於簡單的SQL語句,儲存過程沒什麼優勢
3)如果儲存過程中不一定會減少網路傳輸
4)如果只有一個使用者使用資料庫,那麼儲存過程對安全也沒什麼影響
5)團隊開發時需要先統一標準,否則後期維護成本大
6)在大併發量訪問的情況下,不宜寫過多涉及運算的儲存過程
7)業務邏輯複雜時,特別是涉及到對很大的表進行操作的時候,不如在前端先簡化業務邏輯
定義儲存過程
語法:
create procedure
begin
sql語句;
end
建立儲存過程之前我們必須修改mysql語句預設結束符; 要不能我們不能建立成功
使用delimiter可以修改執行符號
DELIMITER是分割符的意思,因為MySQL預設以";"為分隔符,如果我們沒有宣告分割符,那麼編譯器會把儲存過程當成SQL語句進行處理,則儲存過程的編譯過程會報錯,所以要事先用DELIMITER關鍵字申明當前段分隔符,這樣MySQL才會將";"當做儲存過程中的程式碼,不會執行這些程式碼,用完了之後要把分隔符還原。
語法:
delimiter 新執行符號
mysql> delimiter % 這樣結束符就為%
mysql> create procedureselCg()
-> begin
-> select * from category;
-> end %
呼叫儲存過程
語法:
call 過程名(引數1,引數2);
mysql> call selCg() %
儲存過程引數型別
In引數
特點:讀取外部變數值,且有效範圍僅限儲存過程內部
例子:
mysql> delimiter //
mysql> create procedurepin(in p_in int)
-> begin
-> select p_in;
-> set p_in=2;
-> select p_in;
-> end;
-> //
mysql> delimiter ; 使用完馬上恢復預設的
mysql> set @p_in=1;
等同於
對比下,
例:定義儲存過程 getOneBook,當輸入某書籍 id 後,可以調出對應書籍記錄
mysql>create procedure getOneBook(in b int)
->begin
->select * from books where bId=b;
->end //
Query OK, 0 rows affected (0.01 sec)
mysql>call getOneBook(3);//
+-----+-----------------------------+---------+-----------------------------+-------+------------+--------+-----------+
|bId | bName |bTypeId | publishing |price | pubDate | author | ISBN |
+-----+-----------------------------+---------+-----------------------------+-------+------------+--------+-----------+
| 3 | 網路程式與設計-asp | 2 | 北方交通大學出版社| 43 | 2005-02-01 | 王玥| 75053815x |
+-----+-----------------------------+---------+-----------------------------+-------+------------+--------+-----------+
1 row in set (0.00 sec)
Out引數
特點:不讀取外部變數值,在儲存過程執行完畢後保留新值
mysql> delimiter //
mysql> create procedure pout(out p_out int)
-> begin
-> select p_out;
-> set p_out=2;
-> select p_out;
-> end;
-> //
mysql> delimiter ;
mysql> set @p_out=1;
mysql> call pout(@p_out);
不論你怎麼賦值都是2
mysql> create prorcedure demo(out pa varchar(200))
-> begin
-> select bNameinto pa from books where bId=3;
-> end //
呼叫,執行:
mysql> call demo(@a); //
檢視變數@a 中的值:
mysql> select @a;//
+-----------------------------+
| @a|
+-----------------------------+
| 網路程式與設計-asp |
+-----------------------------+
Inout引數
特點:讀取外部變數,在儲存過程執行完後保留新值<類似銀行存款>
mysql> delimiter //
mysql> create procedure pinout(inout p_inout int)
-> begin
-> select p_inout;
-> set p_inout=2;
-> select p_inout;
-> end;
-> //
mysql> delimiter ;
mysql> set @p_inout=1;
mysql> call pinout(@p_inout);
不加引數的情況
如果在建立儲存過程時沒有指定引數型別,則需要在呼叫的時候指定引數值
mysql> create table t2(id int(11)); 建立表
mysql> create procedure t2(n1 int)
-> begin
-> set @x=0;
-> repeat [email protected][email protected]+1;
-> insert into t2values(@x);
-> until @x>n1
-> end repeat;
-> end;
-> //
mysql> delimiter ;
mysql> call t2(5); 迴圈5次
儲存過程變數的使用
MySQL中使用declare進行變數定義
變數定義:DECLARE variable_name [,variable_name...]datatype [DEFAULT value];
datatype為MySQL的資料型別,如:int, float, date,varchar(length)
變數賦值:SET變數名=表示式值[,variable_name= expression ...]
變數賦值可以在不同的儲存過程中繼承
mysql> create proceduredecl()
-> begin
-> declare name varchar(200);
-> set name=(select bName from bookswhere bId=12);
-> select name;
-> end//
儲存過程語句的註釋
做過開發的都知道,寫註釋是個利人利己的事情。便於理解維護
MySQL註釋有兩種風格
“--“:單行註釋
“/*…..*/”:一般用於多行註釋
例子:
mysql> create proceduredecl() --procedure name is decl
->/*procedure body
->/* start begin */
-> begin
-> declare name varchar(200);
-> set name=(select bName from bookswhere bId=12);
-> select name;
-> end//
儲存過程流程控制語句
變數作用域:
內部的變數在其作用域範圍內享有更高的優先權,當執行到end。變數時,內部變數消失,此時已經在其作用域外,變數不再可見了,應為在儲存過程外再也不能找到這個申明的變數,但是你可以通過out引數或者將其值指派給會話變數來儲存其值。
mysql > DELIMITER //
mysql > CREATE PROCEDUREproc3()
-> begin
-> declare x1 varchar(5) default'outer';
-> begin
-> declare x1 varchar(5) default'inner';
-> select x1;
-> end;
-> select x1;
-> end;
-> //
mysql > DELIMITER ;
條件語句
1:if-then -else語句
2:case語句:
迴圈語句:
1:while ···· end while:
2:repeat···· end repeat:
執行操作後檢查結果,而while則是執行前進行檢查。
3:loop ·····end loop:
loop迴圈不需要初始條件,這點和while迴圈相似,同時和repeat迴圈一樣不需要結束條件, leave語句的意義是離開迴圈。
4:LABLES標號:
標號可以用在begin repeat while或者loop語句前,語句標號只能在合法的語句前面使用。可以跳出迴圈,使執行指令達到複合語句的最後一步。
5:ITERATE迭代
通過引用複合語句的標號,來從新開始複合語句
檢視儲存過程
檢視儲存過程內容:
mysql> show createprocedure demo \G
檢視儲存過程狀態:
mysql> show procedurestatus \G 檢視所有儲存過程
修改儲存過程:
使用alter語句修改
ALTER {PROCEDURE | FUNCTION}sp_name [characteristic ...]
characteristic:
{ CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT 'string'
sp_name引數表示儲存過程或函式的名稱
characteristic引數指定儲存函式的特性
CONTAINS SQL表示子程式包含SQL語句,但不包含讀或寫資料的語句;
NO SQL表示子程式中不包含SQL語句
READS SQL DATA表示子程式中包含讀資料的語句
MODIFIES SQL DATA表示子程式中包含寫資料的語句
SQL SECURITY { DEFINER |INVOKER }指明誰有許可權來執行
DEFINER表示只有定義者自己才能夠執行
INVOKER表示呼叫者可以執行
COMMENT 'string'是註釋資訊。
刪除儲存過程
語法:
方法一:DROP PROCEDURE過程名
mysql> drop procedure p_inout;
方法二:DROPPROCEDURE IF EXISTS儲存過程名
這個語句被用來移除一個儲存程式。不能在一個儲存過程中刪除另一個儲存過程,只能呼叫另一個儲存過程
二:觸發器
什麼是觸發器:
觸發器是一種特殊的儲存過程,它在插入,刪除或修改特定表中的資料時觸發執行,它比資料庫本身標準的功能有更精細和更復雜的資料控制能力
觸發器的作用:
1.安全性
可以基於資料庫的值使使用者具有操作資料庫的某種權利。
可以基於時間限制使用者的操作,例如不允許下班後和節假日修改資料庫資料
可以基於資料庫中的資料限制使用者的操作,例如不允許股票的價格的升幅一次超過10%
2.審計
可以跟蹤使用者對資料庫的操作
審計使用者操作資料庫的語句
把使用者對資料庫的操作寫入審計表
3.實現複雜的資料完整性規則
實現非標準的資料完整性檢查和約束。觸發器可產生比規則更為複雜的限制。與規則不同,觸發器可以引用列或資料庫物件。
例如,觸發器可回退任何企圖吃進超過自己保證金的期貨。
4.實現複雜的非標準的資料庫相關完整性規則。
觸發器可以對資料庫中相關的表進行連環更新。
例如,在auths表author_code列上的刪除觸發器可導致相應刪除在其它表中的與之匹配的行。
觸發器能夠拒絕或回退那些破壞相關完整性的變化,取消試圖進行資料更新的事務
5.實時同步地複製表中的資料
6..自動計算資料值
如果資料的值達到了一定的要求,則進行特定的處理。
例如,如果公司的帳號上的資金低於5萬元則立即給財務人員傳送警告資料
建立觸發器:
語法:
create trigger 觸發器名稱 觸發的時機 觸發的動作 on 表名 for each row 觸發器狀態。
引數說明:
觸發器名稱: 自己定義
觸發的時機: before /after 在執行動作之前還是之後
觸發的動作 :指的激發觸發程式的語句型別<insert ,update,delete>
觸發器建立語法四要素:1.監視地點(table)2.監視事件(insert/update/delete)3.觸發時間(after/before)4.觸發事件(insert/update/delete)
例:當category表中,刪除一個bTypeid=3的圖書分類時,books表中也要刪除對應分類的圖書資訊
mysql> use book;
在category執行刪除前,檢視bTypeId=3的圖書分類:
mysql> select bName,bTypeId from books where bTypeId=3;
建立觸發
mysql> delimiter //
mysql> create trigger delCategory after delete on categoryfor each row
-> delete from books where bTypeId=3;
-> //
刪除bTypeId=3的記錄
mysql> delete from category where bTypeId=3;
檢視:是否還有bTypeId=3的圖書記錄。可以看出已經刪除。
檢視觸發器:
1:檢視建立過程
mysql> show createtrigger delCategory\G
2:檢視觸發器詳細資訊
mysql> showtriggers\G 這個檢視所有的
刪除觸發器:
語法:
drop trigger 觸發器名稱;
mysql> drop trigger delCategory;
思考:觸發器是不是永久保留?
三:事務
什麼是事務:
資料庫事務:(database transaction):事務是由一組SQL語句組成的邏輯處理單元,要不全成功要不全失敗。
事務處理:可以確保非事務性單元的多個操作都能成功完成,否則不會更新資料資源。
資料庫預設事務是自動提交的, 也就是發一條sql它就執行一條。如果想多條 sql放在一個事務中執行,則需要使用事務進行處理。當我們開啟一個事務,並且沒有提交,mysql 會自動回滾事務。或者我們使用 rollback 命令手動回滾事務。
優點:通過將一組操作組成一個,執行時,要麼全部成功,要麼全部失敗的單元。
使程式更可靠,簡化錯誤恢復。
例:
A匯款給B1000元
A賬戶-1000
B賬戶+1000
以上操作對應資料庫為兩個update。這兩個操作屬於一個事物。否則,可能會出現A賬戶錢少了,B賬戶錢沒增加的情況。
事務四大特性:
事務是必須滿足4個條件(ACID)
1、原子性(Autmic):事務在執行性,要做到“要麼不做,要麼全做!”,就是說不允許事務部分得執行。即使因為故障而使事務不能完成,在rollback時也要消除對資料庫得影響!
2、一致性(Consistency):事務必須是使資料庫從一個一致性狀態變到另一個一致性狀態。一致性與原子性是密切相關的。在事務開始之前和結束之後,資料庫的完整性約束沒有被破壞
3、隔離性(Isolation):一個事務的執行不能被其他事務干擾。即一個事務內部的操作及使用的資料對併發的其他事務是隔離的,併發執行的各個事務之間不能互相干擾,這些通過鎖來實現。
4、永續性(Durability):指一個事務一旦提交,它對資料庫中資料的改變就應該是永久性的。接下來的其他操作或故障(比如說宕機等)不應該對其有任何影響。
事務的ACID特性可以確保銀行不會弄丟你的錢,而在應用邏輯中,要實現這點非常難,甚至可以說是不可能完成的任務。
MySQL事務處理的方法:
1、用BEGIN,ROLLBACK,COMMIT來實現
START TRANSACTION | BEGIN [WORK]開啟事務
COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE] 提交當前事務,執行永久操作。
ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE] 回滾當前事務到開始點,取消上一次開始點後的所有操作。
SAVEPOINT 名稱 折返點
2、直接用set來改變mysql的自動提交模式
MYSQL預設是自動提交的,也就是你提交一個QUERY,它就直接執行!
SETAUTOCOMMIT = {0 | 1} 設定事務是否自動提交,預設是自動提交的。
0:禁止自動提交
1:開啟自動提交。
※MYSQL中只有INNODB和BDB型別的資料表才能支援事務處理!其他的型別是不支援!
mysql> set autocommit=0;
mysql> delimiter //
mysql> start transaction;
-> update books setbName="ccc" where bId=1;
-> update books setbName="ddd" where bId=2;
-> commit;//
測試,檢視是否完成修改:
mysql> select bName frombooks where bId=1 or bId=2;//
我們測試回滾操作,首先看我們的資料庫儲存引擎是否為innodb
mysql> show create tablebooks//\G
為MyISAM無法成功啟動事務,雖然提交了,卻無法回滾
修改資料庫儲存引擎為innodb
mysql> alter table booksengine=innodb;
mysql> alter tablecategory engine=innodb;
重新開啟事務,並測試回滾
mysql> set autocommit=0;
mysql> delimiter //
mysql> start transaction;
-> update books set bName="HA"where bId=1;
-> update books set bName="LB"where bId=2;
-> commit;//
mysql> delimiter ;
無法回滾,因為我們commit已經提交了
mysql> delimiter //
mysql> start transaction;update books set bName="AH" where bId=1; update books setbName="BL" where bId=2;// 不提交
mysql> delimiter ;
回滾:
mysql> rollback;
恢復了
轉載於:https://blog.51cto.com/breaklinux/1726769