Mysql 預存程序的學習筆記

來源:互聯網
上載者:User

技術要點

一個預存程序包括名字、參數列表,以及可以包括很多SQL語句的SQL語句集。下面為一個預存程序的定義過程:
create procedure proc_name (in parameter integer)begindeclare variable varchar(20);if parameter=1 thenset variable='MySQL';elseset variable='PHP';end if;insert into tb (name) values (variable);end;


MySQL中預存程序的建立以關鍵字create procedure開始,後面緊跟預存程序的名稱和參數。MySQL的預存程序名稱不區分大小寫,例如PROCE1()和proce1()代表同一個預存程序名。預存程序名不能與MySQL資料庫中的內建函數重名。
預存程序的參數一般由3部分組成。第一部分可以是in、out或inout。in表示向預存程序中傳入參數;out表示向外傳出參數;inout表示定義的參數可傳入預存程序,並可以被預存程序修改後傳出預存程序,預存程序預設為傳入參數,所以參數in可以省略。第二部分為參數名。第三部分為參數的類型,該類型為MySQL資料庫中所有可用的欄位類型,如果有多個參數,參數之間可以用逗號進行分割。
MySQL預存程序的語句塊以begin開始,以end結束。語句體中可以包含變數的聲明、控制語句、SQL查詢語句等。由於預存程序內部語句要以分號結束,所以在定義預存程序前應將語句結束標誌“;”更改為其他字元,並且該字元在預存程序中出現的幾率也應該較低,可以用關鍵字delimiter更改。例如:
mysql>delimiter //


預存程序建立之後,可用如下語句進行刪除,參數proc_name指預存程序名。
drop procedure proc_name


實現過程


(1)MySQL預存程序是在“命令提示字元”下建立的,所以首先應該開啟“命令提示字元”視窗。
(2)進入“命令提示字元”視窗後,首先應該登入MySQL資料庫伺服器,在“命令提示字元”下輸入如下命令:
mysql –u使用者名稱 –p使用者密碼


(3)更改語句結束符號,本執行個體將語句結束符更改為“//”。代碼如下:
delimiter //


(4)建立預存程序前應首先選擇某個資料庫。代碼如下:
use 資料庫名


(5)建立預存程序。
(6)通過call語句調用預存程序。

舉一反三

-- 建表

use test;
create table user(
id mediumint(8) unsigned not null auto_increment,
name char(15) not null default '',
pass char(32) not null default '',
note text not null,
primary key (id)
)engine=Innodb charset=utf8;

-- 樣本一

delimiter //
create procedure proc_name (in parameter integer)
begin
if parameter=0 then
select * from user order by id asc;
else
select * from user order by id desc;
end if;
end;
//
delimiter ;
show warnings;
call proc_name(1);
call proc_name(0);

-- 樣本二

drop procedure proc_name;
delimiter //
create procedure proc_name (in parameter integer)
begin
declare variable varchar(20);
if parameter=1 then
set variable='Windows';
else
set variable='Linux';
end if;
select parameter;
end;
//
delimiter ;
show warnings;
call proc_name(1);
call proc_name(0);

預存程序中使用事務transaction


一.在處理事務時,使用SQLException捕獲SQL錯誤,然後處理; 按照這個推論,我們必須在MySQL預存程序中捕獲SQL錯誤,最後判斷是復原(ROLLBACK)還是提交(COMMIT)。 所以預存程序為:

DELIMITER $$ 
DROP PROCEDURE IF EXISTS  test_sp1 $$ 
CREATE PROCEDURE test_sp1( ) 
    BEGIN 
    DECLARE t_error INTEGER DEFAULT 0; 
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET t_error=1; 
 
        START TRANSACTION; 
            INSERT INTO test VALUES(NULL, 'test sql 001');    
            INSERT INTO test VALUES('1', 'test sql 002');    
 
        IF t_error = 1 THEN 
            ROLLBACK; 
        ELSE 
            COMMIT; 
        END IF; 
 
    END$$ 
DELIMITER ; 

在這個例子中,我們為test_sp1() 定義了一個 SQLEXCEPTION 參數 t_error, 在遇到SQL錯誤時,繼續執行(CONTINUE); 如果執行狀態沒有錯誤,則提交,反之復原!

二.在調用事務時,將事務的執行狀態(即:事務是提交了還是復原了),返回給被調者。

下面給出另一個例子:

CREATE DEFINER=`3dmodelbaseadmin`@`%` PROCEDURE `p_userConfirmPay`(
in p_lID int,
in p_endTime DATETIME,
in p_moneyAfterTax decimal(10,2),
in p_integralAfterTax decimal(10,0),
in p_sellerID int unsigned,
in p_cashOrPoints int,
in p_loginName_site varchar(50),
in p_transactionID_site char(100),
in p_orderID char(100),
in p_remarks_site char(100),
in p_transactionID char(100),
in p_cMEMID INT UNSIGNED,
in p_curTotal DECIMAL(10,2),
in p_curTotalcIntegral decimal(10,0),
in p_remarks char(100))
BEGIN

DECLARE p_cMEMID_site INT;
DECLARE p_balance_site DECIMAL(10,2);
DECLARE p_balance DECIMAL(10,2);
DECLARE p_intBalance_site DECIMAL(10,0);
DECLARE p_intBalance DECIMAL(10,0);

DECLARE t_error INTEGER DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET t_error=1;

START TRANSACTION;

set p_cMEMID_site=(select cMEMID from m_member where cLoginName=p_loginName_site);

update l_memberdownlog set lState=1,endTime=p_endTime where lID=p_lID;

update m_memberMoney set cMoney=cMoney-p_moneyAfterTax,
cIntegral = cIntegral-p_integralAfterTax where cMEMID=p_cMEMID_site;

update m_memberMoney set cMoney=cMoney+p_moneyAfterTax,
cIntegral = cIntegral+p_integralAfterTax where cMEMID=p_sellerID;

if p_cashOrPoints=0 then
  set p_balance_site = (select cMoney from m_memberMoney where cMEMID=p_cMEMID_site);
  INSERT INTO cashDetail ......(此處省略);
else
  set p_intBalance_site = (select cIntegral from m_memberMoney where cMEMID=p_cMEMID_site);
  INSERT INTO integralDetail ......(此處省略);
end if;

update m_memberMoney set totalConsMoney=totalConsMoney+p_curTotal,
totalConsIntegral=totalConsIntegral+p_curTotalcIntegral where cMEMID=p_cMEMID;

IF t_error = 1 THEN
    ROLLBACK;
ELSE
    COMMIT;
END IF;

select t_error;  將事務的執行狀態返回給被調者

MySql預存程序遊標(Cursor)


1、遊標的作用及屬性

遊標的作用就是用於對查詢資料庫所返回的記錄進行遍曆,以便進行相應的操作;遊標有下面這些屬性:

    a、遊標是唯讀,也就是不能更新它;

    b、遊標是不能滾動的,也就是只能在一個方向上進行遍曆,不能在記錄之間隨意進退,不能跳過某些記錄;

    c、避免在已經開啟遊標的表上更新資料。

2、如何使用遊標

使用遊標需要遵循下面步驟:

a、首先用DECLARE語句聲明一個遊標             


DECLARE cursor_name CURSOR FOR SELECT_statement; 
上面這條語句就對,我們執行的select語句返回的記錄指定了一個遊標  
     b、其次需要使用OPEN語句來開啟上面你定義的遊標


OPEN cursor_name; 
     c、接下來你可以用FETCH語句來獲得下一行資料,並且遊標也將移動到對應的記錄上(這個就類似java裡面的那個iterator)。

FETCH cursor_name INTO variable list; 
     d、然後最後當我們所需要進行的操作都結束後我們要把遊標釋放掉。

CLOSE cursor_name; 
在使用遊標時需要注意的是,使用定義一個針對NOT FOUND的條件處理函數(condition handler)來避免出現“no data to fetch”這樣的錯誤,條件處理函數就是當某種條件產生時所執行的代碼,這裡但我們遊標指到記錄的末尾時,便達到NOT FOUND這樣條件,這個時候我們希望繼續進行後面的操作,所以我們會在下面的代碼中看到一個CONTINUE。先看看我們的表格內容:


下面的遊標使用示範擷取庫存量小於100的產品的代碼code,這個代碼純粹示範如何使用,在這裡沒有其他任何意義:)


DELIMITER $$ 
 
DROP PROCEDURE IF EXISTS `test`.`CursorProc` $$ 
CREATE PROCEDURE `test`.`CursorProc` () 
BEGIN 
 DECLARE  no_more_products, quantity_in_stock INT DEFAULT 0; 
 DECLARE  prd_code VARCHAR(255); 
 DECLARE  cur_product CURSOR FOR   SELECT code FROM products;  /*First: Delcare a cursor,首先這裡對遊標進行定義*/ 
 DECLARE  CONTINUE HANDLER FOR NOT FOUND  SET  no_more_products = 1; /*when "not found" occur,just continue,這個是個條件處理,針對NOT FOUND的條件*/ 
 
 /* for  loggging information 建立個暫存資料表格來保持*/ 
 CREATE TEMPORARY TABLE infologs ( 
 Id int(11) NOT NULL AUTO_INCREMENT, 
 Msg varchar(255) NOT NULL, 
 PRIMARY KEY (Id) 
 ); 
 
 OPEN  cur_product; /*Second: Open the cursor 接著使用OPEN開啟遊標*/ 
 FETCH  cur_product INTO prd_code; /*Third: now you can Fetch the row 把第一行資料寫入變數中,遊標也隨之指向了記錄的第一行*/ 
 
 REPEAT 
 
 SELECT  quantity INTO quantity_in_stock 
 FROM  products 
 WHERE  code = prd_code; 
  
 IF  quantity_in_stock < 100 THEN 
 INSERT  INTO infologs(msg) 
 VALUES  (prd_code); 
 END  IF; 
 FETCH  cur_product INTO prd_code; 
 
 UNTIL  no_more_products = 1 
 END REPEAT; 
 CLOSE  cur_product;  /*Finally: cursor need be closed 用完後記得用CLOSE把資源釋放掉*/ 
 SELECT *  FROM infologs; 
 DROP TABLE  infologs; 
END $$ 
 
DELIMITER ; 


下面是最終的結果:

<img src="http://www.111cn.net /uploads/201208/18/1345302174_3501.png" alt=""> 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.