mysql存儲過程

1、數據庫操做存儲過程原子性

(1)添加事務 事務結束必須commit或者 rollback 結束事務java

CREATE PROCEDURE test_proc_ins(  
IN i_id INT,  
IN i_name VARCHAR(100)  
)  
BEGIN  
start transaction; --整個存儲過程指定爲一個事務  
           INSERT INTO testproc VALUES (i_id, i_name);  
           INSERT INTO testproc VALUES (i_id+1, i_name); -- 這裏把id+1,避免主鍵衝突  
commit; -- 語句1。必須主動提交  
END;

能夠同時出現多個事務,這樣能夠保證整個存儲過程回滾,不會由於某一個sql異常而破壞數據庫特性mysql

CREATE PROCEDURE test_proc_ins(  
IN i_id INT,  
IN i_name VARCHAR(100),  
OUT o_ret INT)  
BEGIN  
start transaction;  
           INSERT INTO testproc VALUES (i_id, i_name);  
           INSERT INTO testproc VALUES (i_id+1,i_name);  
           commit; -- 語句1,提交後,事務已結束  
           set o_ret = 1;  
           start transaction; -- 再啓一個事務  
           INSERT INTO testproc VALUES (i_id+2,i_name); -- 語句2  
           INSERT INTO testproc VALUES (i_id+2,i_name); -- 語句3  
           set o_ret = 2;  
           commit; -- 數據正常的狀況下,須要再次commit以結束事務  
END;

2、多結果集返回與java獲取

存儲過程常常須要返回多個結果集。 MySQL 中直接用 select 便可返回結果集。而 Oracle 則須要使用遊標來返回結 果 集。這一點 Mysql 相對比較方便,以下代碼便可實現輸出兩個結果集(oracle之後再說)sql

存儲過程:

CREATE PROCEDURE test_proc_multi_select()  
BEGIN  
         select * from testproc;  
         select * from testproc where id=1;  
END;

處理方式:

con = MConnection.getConn();  
       String sql = "{call test_proc_multi_select()}";  
      cs = con.prepareCall(sql);  
      boolean hadResults = cs.execute();  
      int i=0;  
      while (hadResults) {  
          System.out.println("result No:----"+(++i));  
          ResultSet rs = cs.getResultSet();  
          while (rs != null && rs.next()) {  
             int id1 = rs.getInt(1);  
             String name1 = rs.getString(2);  
             System.out.println(id1 + ":" + name1);  
          }  
          hadResults = cs.getMoreResults(); //檢查是否存在更多結果集  
      }

3、存儲過程處理分頁

而 MySQL 的存儲過程分頁必須經過動態 sql 來執行。分頁對應的 offset 和 row_count 必須先用 concat 函數變成字符串組裝到 sql 中(如語句 1 ),而不能直接使用(如語句 2 , Mysql 不支持)。數據庫

CREATE PROCEDURE test_proc_multi_select(IN i_pageIndex INT, IN i_pageSize INT)  
BEGIN  
         declare stmt varchar(2000);  
         set @sql = concat('select * from testproc limit ',(i_pageIndex-1) * i_pageSize,' , ',i_pageSize); -- 語句1組裝sql  
         prepare stmt from @sql; -- 獲得prepare stmt  
         execute stmt; -- 執行select  
         -- ////如下方式編譯不能經過!  
         -- select * from testproc limit (i_pageIndex-1)*i_pageSize,i_pageSize; -- 語句2  
END;  


CREATE PROCEDURE test_proc_param_select(IN i_name VARCHAR(100),IN i_pageIndex INT, IN i_pageSize INT)  
BEGIN  
     declare stmt varchar(2000);  
     set @sql = concat('select * from testproc where name like ''%',i_name,'%'' limit ',(i_pageIndex-1) * i_pageSize,',',i_pageSize); --注意like後兩個單引號表示一個。  
     prepare stmt from @sql;  
     execute stmt;  
END;

4、存儲過程異常處理oracle

不但願存儲過程拋出錯誤停止執行,而是但願返回一個錯誤碼。 MySQL 支持異常處理,經過定義 CONTINUE/EXIT 異常處理的 HANDLER 來捕獲 SQLWARNING/NOT FOUND/SQLEXCEPTION (警告 / 無數據 / 其餘異常)。其中, FOR 後面能夠改成 SQLWARNING, NOT FOUND, SQLEXCEPTION 來指示全部異常都處理,至關於 Oracle 中的 others 。函數

通過異常處理後,能夠避免拋出錯誤,而是定義一個返回參數 o_ret 賦予特殊值來表示失敗,這樣,在 Java 代碼中,能夠經過獲取返回值而不是捕獲異常的方式來處理業務邏輯。例如將返回值設置爲 -1code

CREATE PROCEDURE test_proc_ins1(  
         IN i_id INT,  
         IN i_name VARCHAR(100),  
         OUT o_ret INT)  
BEGIN  
         DECLARE EXIT HANDLER FOR SQLSTATE '23000' set o_ret = -1;  
-- 也能夠這樣使用:  
-- DECLARE EXIT HANDLER FOR SQLWARNING,NOT FOUND,SQLEXCEPTION set o_ret=-1;  
         INSERT INTO testproc VALUES (i_id,i_name);  
         INSERT INTO testproc VALUES (i_id,i_name);  
         set o_ret = 1;  
END;

5、SEQUENCE的實現

在 Oracle 中, sequence 提供多表多字段可共用一個不重複值。 MySQL 中存在自增列,基本能夠知足 PK 的要求。但自增列存在限制:事務

a. 只能用於表中的一個字段,一張不能同時存在兩個以上的自增列 ;rem

b. 自增列必須被定義爲 key ( PK 或 FK ) ;字符串

c. 自增列不能被多個表共用 ;

d. 當 insert 語句不包括自增字段或將其值設置爲 NULL 時,該值會自動填上。

在不要求字段順序遞增的狀況下,能夠在 Mysql 中實現序列:
DROP TABLE IF EXISTS sequence;    
   
-- 建sequence表,指定seq列爲無符號大整型,可支持無符號值:0(default)到18446744073709551615(0到2^64–1)。  
CREATE TABLE sequence (  
     name              VARCHAR(50) NOT NULL,    
         current_value     BIGINT UNSIGNED NOT NULL DEFAULT 0,    
         increment         INT NOT NULL DEFAULT 1,    
         PRIMARY KEY (name)   -- 不容許重複seq的存在。  
) ENGINE=InnoDB;    
   
   
DELIMITER /   
   
DROP FUNCTION IF EXISTS currval /  
   
CREATE FUNCTION currval(seq_name VARCHAR(50))   
RETURNS BIGINT  
BEGIN  
         DECLARE value BIGINT;  
         SELECT current_value INTO value  
         FROM sequence  
         WHERE upper(name) = upper(seq_name); -- 大小寫不區分.  
         RETURN value;  
END;  
/  
   
DELIMITER ;   
   
   
DELIMITER /  
   
DROP FUNCTION IF EXISTS nextval /  
   
CREATE FUNCTION nextval (seq_name VARCHAR(50))    
RETURNS BIGINT    
BEGIN    
         DECLARE value BIGINT;  
         UPDATE sequence    
         SET current_value = current_value + increment    
         WHERE upper(name) = upper(seq_name);  
         RETURN currval(seq_name);    
END;  
/  
   
DELIMITER ;   
   
DELIMITER /  
   
DROP FUNCTION IF EXISTS setval /    
   
CREATE FUNCTION setval (seq_name VARCHAR(50), value BIGINT)    
RETURNS BIGINT  
BEGIN   
         UPDATE sequence    
         SET current_value = value    
         WHERE upper(name) = upper(seq_name);    
         RETURN currval(seq_name);    
END;  
/  
   
DELIMITER ;

在 SQL 中使用序列:

建立序列,往sequence表插入值便可:  
mysql> insert into sequence set name='myseq';  
查看當前已建序列:  
mysql> select * from sequence;  
+-------+---------------+-----------+  
| name  | current_value | increment |  
+-------+---------------+-----------+  
| myseq |             0 |         1 |  
+-------+---------------+-----------+  
1 row in set (0.00 sec)  
得到序列的下一個值,第一次使用,所以值爲1:  
mysql> select nextval('myseq');  
+------------------+  
| nextval('myseq') |  
+------------------+  
|                1 |  
+------------------+  
1 row in set (0.00 sec)

在存儲過程當中使用序列(以 sql code 1-1 中建立的 testproc 表爲例),此存儲過程返回插入後的 ID ,若是插入失敗,則返回 -1 :

create procedure test_sequence(IN i_name VARCHAR(100),  
         OUT o_ret BIGINT)  
BEGIN  
         DECLARE EXIT HANDLER FOR SQLWARNING,NOT FOUND,SQLEXCEPTION set o_ret = -1;  
         set o_ret = nextval('myseq');  
         INSERT INTO testproc VALUES (o_ret,i_name);  
         INSERT INTO testproc3 VALUES (o_ret,i_name);  
END;
相關文章
相關標籤/搜索