(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;