本文內容:前端
存儲過程 mysql
觸發器sql
事務數據庫
1、存儲過程大多數SQL語句都是針對一個或多個表的單條語句。並不是全部的操做都怎麼簡單。常常會有一個完整的操做須要多條才能完成。存儲過程(Stored Procedure)是在大型數據庫系統中,一組爲了完成特定功能的SQL 語句集,存儲在數據庫中通過第一次編譯後再次調用不須要再次編譯,用戶經過指定存儲過程的名字並給出參數(若是該存儲過程帶有參數)來執行它。存儲過程是數據庫中的一個重要對象,任何一個設計良好的數據庫應用程序都應該用到存儲過程。express
(1).存儲過程加強了SQL語言的功能和靈活性。存儲過程能夠用流控制語句編寫,有很強的靈活性,能夠完成複雜的判斷和較複雜的運算。編程
(2).存儲過程容許標準組件是編程。存儲過程被建立後,能夠在程序中被屢次調用,而沒必要從新編寫該存儲過程的SQL語句。並且數據庫專業人員能夠隨時對存儲過程進行修改,對應用程序源代碼毫無影響。安全
(3).存儲過程能實現較快的執行速度。若是某一操做包含大量的Transaction-SQL代碼或分別被屢次執行,那麼存儲過程要比批處理的執行速度快不少。由於存儲過程是預編譯的。在首次運行一個存儲過程時查詢,優化器對其進行分析優化,而且給出最終被存儲在系統表中的執行計劃。而批處理的Transaction-SQL語句在每次運行時都要進行編譯和優化,速度相對要慢一些。網絡
(4).存儲過程能過減小網絡流量。針對同一個數據庫對象的操做(如查詢、修改),若是這一操做所涉及的Transaction-SQL語句被組織程存儲過程,那麼當在客戶計算機上調用該存儲過程時,網絡中傳送的只是該調用語句,從而大大增長了網絡流量並下降了網絡負載。併發
(5).存儲過程可被做爲一種安全機制來充分利用。系統管理員經過執行某一存儲過程的權限進行限制,可以實現對相應的數據的訪問權限的限制,避免了非受權用戶對數據的訪問,保證了數據的安全。ide
1)可移植性差
2)對於簡單的SQL語句,存儲過程沒什麼優點
3)若是存儲過程當中不必定會減小網絡傳輸
4)若是隻有一個用戶使用數據庫,那麼存儲過程對安全也沒什麼影響
5)團隊開發時須要先統一標準,不然後期維護成本大
6)在大併發量訪問的狀況下,不宜寫過多涉及運算的存儲過程
7)業務邏輯複雜時,特別是涉及到對很大的表進行操做的時候,不如在前端先簡化業務邏輯
語法:
create procedure 過程名(參數1,參數2....)
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() %
特色:讀取外部變量值,且有效範圍僅限存儲過程內部
例子:
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)
特色:不讀取外部變量值,在存儲過程執行完畢後保留新值
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 |
+-----------------------------+
特色:讀取外部變量,在存儲過程執行完後保留新值<相似銀行存款>
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 set@x=@x+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;
方法二:DROP PROCEDURE 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)
一、原子性(Autmic):事務在執行性,要作到「要麼不作,要麼全作!」,就是說不容許事務部分得執行。即便由於故障而使事務不能完成,在rollback時也要消除對數據庫得影響!
二、一致性(Consistency):事務必須是使數據庫從一個一致性狀態變到另外一個一致性狀態。一致性與原子性是密切相關的。在事務開始以前和結束以後,數據庫的完整性約束沒有被破壞
三、 隔離性(Isolation):一個事務的執行不能被其餘事務干擾。即一個事務內部的操做及使用的數據對併發的其餘事務是隔離的,併發執行的各個事務之間不能互相干擾,這些經過鎖來實現。
四、 持久性(Durability):指一個事務一旦提交,它對數據庫中數據的改變就應該是永久性的。接下來的其餘操做或故障(好比說宕機等)不該該對其有任何影響。
事務的ACID特性能夠確保銀行不會弄丟你的錢,而在應用邏輯中,要實現這點很是難,甚至能夠說是不可能完成的任務。
一、 用BEGIN,ROLLBACK,COMMIT來實現
START TRANSACTION | BEGIN [WORK] 開啓事務
COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE] 提交當前事務,執行永久操做。
ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE] 回滾當前事務到開始點,取消上一次開始點後的全部操做。
SAVEPOINT 名稱 折返點
二、 直接用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;
恢復了