您的位置:首页 > 数据库 > Oracle

Oracle 存储过程

2018-07-25 18:06 176 查看

某厂面试归来,发现自己落伍了!>>>

一、存储过程结构:

1.创建语句:

create [or replace] procedure 存储过程名(入参 [in|out] 入参类型[,入参 [in|out] 入参类型])
is
定义变量区
变量名 变量类型[:=变量值];
begin
PL/SQL 程序块

  Exception  
    When 具体异常/自定义异常 then
        处理逻辑
    When others then
        其他异常处理逻辑
       Rollback; --回滚没有commit的数据
end [存储过程名];
 

2.结构解析:

我们对存储过程的结构进行进一步的解释:

a) 使用"[]"包含的语句是可写可不写的,写或不写大部分情况下都是有区别的,比如or replace, 看单词含义就知道,如果写了这个语句,系统存在同名存储过程,执行该创建语句将会覆盖原有存储过程。

b) 参数: 参数名 [in|out] 参数类型 
--in表示入参,在存储过程中不可赋值;类似于java方法中的final 入参;
--out表示出参,在传入存储过程之前的任何赋值都无效,如果在存储过程中未被赋值,则出参为空;
--都有表示即为入参也为出参,可以理解在java中传入方法的变量,存储过程中可以使用,也可以改变其值;
--可以同时使用,也可以单独使用,也可以不使用,不使用默认为in;

c) 定义变量区:

   在存储过程中使用的变量,必须在此定义(隐式游标除外)并且指定宽度,定义变量大致是这个结构:变量名 变量类型[:=变量值];适用于大部分数据库已有的变量类型,如varchar2,number,date等等,但是当游标等特殊数据时,会使用到特定结构,这个后续增加章节细说。

d) PL/SQL程序块

     也叫逻辑处理模块,是由各种语法组成、对数据库对象进行操作的模块,后面会细说。

e) 异常处理模块

    异常处理模块由固定语法组成,可以捕获系统的具体异常(如no_data_found,too_many_rows等等),也可以在变量区定义自定义异常,在程序块中主动抛出,在异常处理模块捕获:

    定义异常变量: v_exception excetion;

    程序块中抛出: raise v_exception;

    异常处理模块捕获: when v_exception then dbms_output.putline("抛出异常");

f) 结束语句 由关键词end [存储过程名] 结束存储过程。 

3.包和存储过程

包也是oracle中的一种对象类型,它可以包含存储过程,自定义类型,自定义游标等等,拓展存储过程的用法。

后续再增加章节细说。

 

二、存储过程中使用的语法

1.变量赋值语句:

    a)变量名:=变量值;

    b) select XX into 变量名 from tableName where ...;

    c) 动态语句赋值: execute immediate '只查询出一个值的SQL语句'  into 变量名;

2.条件语句(注意Oracle中的相等条件是用单独一个等号"=",如 if v_num = 0 then ...)

  a) if 条件 [and|or 条件] then

     逻辑处理语句;

   elsif 条件 [and|or 条件] then

     逻辑处理语句;

   else

    逻辑处理语句;

   end if;

b)case 变量 

      when 变量值 then

           逻辑处理语句;

      when  变量值 then 

          逻辑处理语句;

   end case;

c) case when 条件 [and|or 条件] then 逻辑处理语句; end case;

3.循环语句

  a) 普通for循环(其实这是一个隐式游标)

  for i in 0..100
     loop

     dbms_output.putline(i);
  end loop;

  b)普通while循环

       while 条件 [and|or 条件]

         loop 

         逻辑处理;

       end loop;

   c) 隐式游标循环

       for data in select * from tableName

         loop

         dbms_output.putline(data.colName||'---'||data.colName);

       end loop;

   4.普通DML语句

      直接写就可以了,但是如果要提交的话需要在语句结束后加上commit;

  5.DDL语句

     存储过程中是不可以直接执行DDL语句的,但是可以通过动态语句来执行:

     execute immediate 'DDL语句字符串';

     如果语句中含有 “ ' ” 单引号在拼写的时候 使用 '' 即可

    如:     

6.调用存储过程

    declare
      定义出参,入参
    begin
       存储过程名(出入参);
     end;

三、java中调用

在java中调用存储过程和调用其他SQL方式一样,唯一不同的是语句,存储过程的语句是 call 存储过程名(?,?)

我这里只说明一下基本的数据库连接三对象的操作,由于现在基本上没有人使用这个来对数据库进行操作,都是使用各框架封装好的,所以各框架对存储过程的调用请自行查询:

1.无返回值的存储过程
public static void main(String[] args ){
    String driver = "oracle.jdbc.driver.OracleDriver";
    String strUrl = "jdbc:oracle:thin:@127.0.0.1:1521:test";
    Statement stmt = null;
    ResultSet rs = null;
    Connection conn = null;
    CallableStatement cstmt = null;
    try {
      Class.forName(driver);
      conn = DriverManager.getConnection(strUrl, "user", "password");
      CallableStatement proc = null;
      proc = conn.prepareCall("{ call 存储过程名(?,?) }");
        //设置入参
      proc.setString(1, "100");
      proc.setString(2, "TestOne");
        //执行
      proc.execute();
    }catch (Exception e) {
      e.printStackTrace();
    }finally{
        //各种close
    }
}
2.有返回值的存储过程(非列表)
    public static void main(String[] args ){
        String driver = "oracle.jdbc.driver.OracleDriver";
        String strUrl = "jdbc:oracle:thin:@127.0.0.1:1521:test";
        Statement stmt = null;
        ResultSet rs = null;
        Connection conn = null;
        try {
          Class.forName(driver);
          conn = DriverManager.getConnection(strUrl, "user", "password");
          CallableStatement proc = null;
          proc = conn.prepareCall("{ call 存储过程名(?,?) }");
          //设置入参
          proc.setString(1, "100");
          //设置出参类型
          proc.registerOutParameter(2, Types.VARCHAR);
          //执行
          proc.execute();
          //获取出参值
          String testPrint = proc.getString(2);
          System.out.println(testPrint);
        }catch (Exception e) {
          e.printStackTrace();
        }finally{
          //各种close
        }
    }
注意,这里的proc.getString(2)中的数值2是指存储过程第二个参数。

基本的存储过程使用差不多就是这些了,下面写一个testProcedure来说明一下:

create or replace procedure testProcedure(p_date varchar2,o_code out varchar2)
is
--定义变量 可以直接初始化
v_date date:=to_date(p_date,'yyyyMMdd');
--后续可操作变化
v_message varchar2(4000);
v_step varchar2(100);
v_tablename varchar2(200):='test_user';
v_flag number:=1;
v_exception exception;
begin

v_step:='1';
--调试输出
DBMS_OUTPUT.put_line(to_char(v_date,'yyyy-MM-dd HH24:mi:ss'));

v_message:='Hello World!';
--循环
v_step:='2';
for i in 0..100
loop
DBMS_OUTPUT.put_line(v_message||' '||i);
end loop;

while v_flag<100
loop
v_flag:=v_flag+1;
DBMS_OUTPUT.put_line(v_message||'v_flag '||v_flag);
end loop;

case v_step
when '2'then
DBMS_OUTPUT.put_line(v_message||''||2);
when '3'then
DBMS_OUTPUT.put_line(v_message||''||3);
end case;

case when v_step='2' then
DBMS_OUTPUT.put_line(v_message||''||2);
end case;

v_step:='3';
select count(*) into v_flag from user_tables where table_name = v_tablename;
--动态语句
v_step:='4';
execute immediate 'select count(*) from user_tables where table_name=upper('''||v_tablename||''')' into v_flag;
if v_flag=0 and v_flag!=1 then
--不存在就创建表
v_step:='5';
execute immediate 'create table '||v_tablename||'(id varchar2(32),username varchar2(100),password varchar2(32))';
o_code:='创建表~';

else
--存在就删掉表
v_step:='6';
execute immediate 'drop table  '||v_tablename;
o_code:='删除表~';
raise v_exception;
end if;
Exception
when v_exception then
v_message:= sqlcode || sqlerrm;
dbms_output.put_line('测试一下自定义异常报错捕获');
dbms_output.put_line(v_message);
When others then
v_message:= sqlcode || sqlerrm;
dbms_output.put_line('在第'||v_step||'步报错:');
dbms_output.put_line(v_message);
Rollback;
end testProcedure;

这个存储过程包含了一些基本语法和操作,可以用来做参考

(window.slotbydup = window.slotbydup || []).push({ id: "u5894387", container: "_0hv0l6ey3zro", async: true });
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Oracle