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;
相关文章
相关标签/搜索