1. 程式人生 > 實用技巧 >MYSQL--儲存過程-觸發器-事務

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

過程名(引數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() %

wKioL1Z3kg-ha13mAAAq2PXJ_lA385.png

儲存過程引數型別

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;


wKioL1Z3jHrzOBvgAAAd9htloAs321.png

wKiom1Z3jIfjbMUFAAAUeYO5L70080.png


等同於


wKioL1Z3jNKhgSDfAAAbXrgBW8s241.png

wKioL1Z3jNPBGqAJAAAUeYO5L70478.png




對比下,

例:定義儲存過程 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);


wKioL1Z3jQ-THxNQAAAavCQ0Gyc825.png

wKioL1Z3jRCC6_hUAAAUR5UzcC0189.png




不論你怎麼賦值都是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);

wKioL1Z3jTuAZwiyAAAaTClngSg655.png

wKioL1Z3jTvQcMcbAAAVCpwsWRY138.png

不加引數的情況

如果在建立儲存過程時沒有指定引數型別,則需要在呼叫的時候指定引數值

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次

wKiom1Z3jVvQuLfsAAAVhXSOSmQ811.png

儲存過程變數的使用

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//

wKiom1Z3jf7iMVq_AAAXkCaQebg554.png

儲存過程語句的註釋

做過開發的都知道,寫註釋是個利人利己的事情。便於理解維護

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語句

wKiom1Z3jiPgwKTXAAClPqvxv3s750.png

2:case語句:

wKiom1Z3jj2Dq7YvAACta4YPmlA649.png

迴圈語句:

1:while ···· end while:

wKiom1Z3jl-znepIAABpp0NI8yM438.png

2:repeat···· end repeat:

執行操作後檢查結果,而while則是執行前進行檢查。

wKiom1Z3jnrji6D-AABv36OuZCk912.png

3:loop ·····end loop:

loop迴圈不需要初始條件,這點和while迴圈相似,同時和repeat迴圈一樣不需要結束條件, leave語句的意義是離開迴圈。

wKiom1Z3jpzwpd4cAAB6QcxoL48393.png

4:LABLES標號:

標號可以用在begin repeat while或者loop語句前,語句標號只能在合法的語句前面使用。可以跳出迴圈,使執行指令達到複合語句的最後一步。

5:ITERATE迭代

通過引用複合語句的標號,來從新開始複合語句

wKiom1Z3jreBmR42AAB6QcxoL48634.png

檢視儲存過程

檢視儲存過程內容:

mysql> show createprocedure demo \G

wKiom1Z3jtDCORtzAAA5_7Q5tBY580.png

檢視儲存過程狀態:

mysql> show procedurestatus \G 檢視所有儲存過程

wKiom1Z3ju2BmGaBAAAx8gvEGbA805.png

修改儲存過程:

使用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. 1.安全性

可以基於資料庫的值使使用者具有操作資料庫的某種權利。

可以基於時間限制使用者的操作,例如不允許下班後和節假日修改資料庫資料

可以基於資料庫中的資料限制使用者的操作,例如不允許股票的價格的升幅一次超過10%

  1. 2.審計

可以跟蹤使用者對資料庫的操作

審計使用者操作資料庫的語句

把使用者對資料庫的操作寫入審計表

  1. 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;

wKioL1Z3jyPCYzbtAAAy5Nvxyeg939.png

建立觸發

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的圖書記錄。可以看出已經刪除。

wKioL1Z3jzyhIzAwAAAYD1ijY_E302.png


檢視觸發器:

1:檢視建立過程

mysql> show createtrigger delCategory\G

wKiom1Z3j2OTVTZMAAA759T9JiE296.png

2:檢視觸發器詳細資訊

mysql> showtriggers\G 這個檢視所有的

wKiom1Z3j4iC2wxPAAA3W9R1KUw844.png

刪除觸發器:

語法:

drop trigger 觸發器名稱;

mysql> drop trigger delCategory;

wKiom1Z3j6CixsBwAAAS824O6n8335.png

思考:觸發器是不是永久保留?

三:事務

什麼是事務:

資料庫事務:(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;//

wKiom1Z3j8OSYP4OAAAdXJFTRus350.png

我們測試回滾操作首先看我們的資料庫儲存引擎是否為innodb

mysql> show create tablebooks//\G

wKioL1Z3j-3A8M5wAABKwwWcATI265.png

為MyISAM無法成功啟動事務,雖然提交了,卻無法回滾

修改資料庫儲存引擎為innodb

mysql> alter table booksengine=innodb;

mysql> alter tablecategory engine=innodb;


wKioL1Z3kCLy5_FFAAAREcdUCSA542.png

wKiom1Z3kBXzik1YAAAkvQ6irFI764.png




重新開啟事務,並測試回滾

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 ;

wKioL1Z3kHDi0ajxAAAbqUTPcX8808.png

無法回滾,因為我們commit已經提交了

mysql> delimiter //

mysql> start transaction;update books set bName="AH" where bId=1; update books setbName="BL" where bId=2;// 不提交

mysql> delimiter ;

wKioL1Z3kJzwejl8AAAblFhlmCI623.png


回滾:

mysql> rollback;

wKiom1Z3kKyDqHomAAAbm65s0VU019.png

恢復了





轉載於:https://blog.51cto.com/breaklinux/1726769