(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;
存儲過程常常須要返回多個結果集。 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(); //檢查是否存在更多結果集 }
而 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;
在 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;