一、概述

如果想要执行存储过程,我们应该使用 CallableStatement 接口。

CallableStatement 接口继承自PreparedStatement 接口。所以CallableStatement 接口包含有Statement 接口和PreparedStatement 接口定义的全部方法,但是并不是所有的方法我们都要使用,主要使用的方法有这样几个:

CallableStatement 常用方法:

返回类型 方法签名 说明
boolean execute()

执行 SQL 语句,如果第一个结果是 ResultSet 对
象,则返回 true;如果第一个结果是更新计数或者没
有结果,则返回 false

void

registerOutParameter(int parameterIndex,int sqlType)

按顺序位置parameterIndex 将OUT 参数注册为
JDBC 类型sqlType,sqlType 为Types 类中的常量

Type

getType(int parameterIndex)

根据参数的序号获取指定的 JDBC 参数的值。第一
个参数是 1,第二个参数是 2,依此类推

我们可以使用execute()方法来执行存储过程。CallableStatement 为所有的数据库提供了一种统一的标准形式调用存储过程。所以,你将会看到我们使用execute()调用存储过程的语法与在Oracle 中会所有不同。

为了获得存储过程或函数的返回值,我们需要使用 registerOutParameter()方法将返回的参数注册为JDBC 的类型。 registerOutParameter()方法的第一个参数是参数的序号,第一个为1,第二个为2,以此类推。第二个参数需要一个int 值,用来标记JDBC 的类型,我们可以使用java.sql.Types 类中的常量来设置这个参数。比如VARCHAR、DOUBLE 等类型。如果类型不够用,也可以从具体数据库的驱动中寻找合适的类型常量。如果存储过程或函数有返回值,这个方法是必须要调用的,否则无法得到返回值,甚至会发生异常。

CallableStatement 接口中定义了很多get 方法,用于获取存储过程返回的值,根据值的类型不同,你可以使用不同get 方法,比如getInt()、getString()、getDouble()等等。
我们看一下使用CallableStatement 接口执行存储过程和函数的语法格式。

存储过程:{call <procedure-name>[(<arg1>,<arg2>, ...)]}
函数:{?= call <procedure-name>[(<arg1>,<arg2>, ...)]}

如果要调用存储过程,则使用第一种语法,就是开头不带问号的语法,call 后面是过程名,
如果没有参数,可以省略小括号。

如果要调用函数,则使用第二种语法,开头带有一个问号加等号,实际上这个问号就是一个占位符,这个问号总是调用函数的第一个占位符。其它部分与过程的语法相同

二、CallableStatement 执行存储过程

2.1、建立基类

public class BaseDao {
protected Connection conn;
protected PreparedStatement ps;
protected ResultSet rs;
//建立连接
public boolean getConnection(){
String driver=ConfigManager.getInstance().getString("jdbc.driver_class");
String url=ConfigManager.getInstance().getString("jdbc.connection.url");
String username=ConfigManager.getInstance().getString("jdbc.connection.username");
String password=ConfigManager.getInstance().getString("jdbc.connection.password");
try {
Class.forName(driver);
conn=DriverManager.getConnection(url,username, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
return false;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
return true;
}
//增加,修改,删除
public int executeUpdate(String sql, Object[] params){
getConnection();
int updateRow=0;
try {
ps=conn.prepareStatement(sql);
//填充占位符
for(int i=0;i<params.length;i++){
ps.setObject(i+1, params[i]);
}
updateRow = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
return updateRow;
}
//查询
  public ResultSet executeSQL(String sql, Object[] params){
    getConnection();
      try {
        ps=conn.prepareStatement(sql);
        //填充占位符
        for(int i=0;i<params.length;i++){
          ps.setObject(i+1, params[i]);
        }
        rs = ps.executeQuery();
      } catch (SQLException e) {
        e.printStackTrace();
      }
      return rs;
  }
// 关闭资源
  public boolean closeResource() {
    if(rs!=null){
      try {
        rs.close();
      } catch (SQLException e) {
        e.printStackTrace();
        return false;
        }
      }
    if(ps!=null){
      try {
        ps.close();
      } catch (SQLException e) {
        e.printStackTrace();
        return false;
      }
    }
    if(conn!=null){
      try {
        conn.close();
      } catch (SQLException e) {
        e.printStackTrace();
        return false;
        }
      }
      return true;
    }
}

2.2、执行不带参但是有返回值的存储过程

新建类来继承上面的类也可以继承,下面建立存储过程

--查询emp表记录数
CREATE OR REPLACE PROCEDURE getEmpCount(v_count OUT NUMBER)
AS
BEGIN
SELECT COUNT(*) INTO v_count FROM emp;
END;

调用

//执行不带参但是有返回值的存储过程获取emp表总记录数
public int getTotalCountProc(){
  //定义一个变量来接收结果
  int totalCount=0;
  //声明CallableStatement对象
  CallableStatement proc=null;
  String sql="{call getEmpCount(?)}";
  try {
//建立连接
getConnection();
//CallableStatement对象
proc=conn.prepareCall(sql);
//将数据库对象数据类型注册为java中的类型
proc.registerOutParameter(1, Types.INTEGER);
//执行
proc.execute();
//接收返回值
totalCount=proc.getInt(1);
    } catch (SQLException e) {
e.printStackTrace();
    }
    return totalCount;
}

2.3、执行带参带返回值的存储过程

--根据部门编号和姓名查询人数
CREATE OR REPLACE PROCEDURE getEmpCount(v_deptno NUMBER, v_ename VARCHAR2,v_count OUT NUMBER)
AS
BEGIN
SELECT COUNT(*) INTO v_count FROM emp
WHERE ename LIKE '%'||v_ename||'%' AND deptno=v_deptno;
END;
//执行带参带返回值的存储过程
public int getTotalCountProc1(int deptno,String ename){
  //定义一个变量来接收结果
  int totalCount=0;
  //声明CallableStatement对象
  CallableStatement proc=null;
  String sql="{call getEmpCount(?,?,?)}";
  //建立连接
  getConnection();
  //CallableStatement对象
  try {
proc=conn.prepareCall(sql);
//设置占位符
//Object [] params={deptno,ename};
//只设置输入参数即可
proc.setInt(1, deptno);
proc.setString(2, ename);
//proc.setInt(3, totalCount);
////将数据库对象数据类型注册为java中的类型,将输出参数转换
proc.registerOutParameter(3, Types.INTEGER);
//执行
proc.execute();
//获取结果
totalCount=proc.getInt(3);
    } catch (SQLException e) {
e.printStackTrace();
    }finally{
this.closeResource();
if(proc!=null){
try {
proc.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
    }
    return totalCount;
}

2.3、执行返回值为游标的存储过程

--查询员工所有信息
CREATE OR REPLACE PROCEDURE emp_cur(emp_cur OUT SYS_REFCURSOR)
AS
BEGIN
OPEN emp_cur FOR SELECT * FROM emp;
END;
//执行返回值为游标的存储过程 游标名emp_cur
public List<Emp> getempProc1(){
List<Emp> emplist=new ArrayList<Emp>();
String sql="{call emp_cur(?) }";
//声明CallableStatement对象
CallableStatement proc=null;
//建立连接
getConnection();
try {
//执行
proc=conn.prepareCall(sql);
//注册类型为数据库游标类型
proc.registerOutParameter(1, oracle.jdbc.OracleTypes.CURSOR);
//接收结果集
proc.execute();
//获取结果第一个对象
rs=(ResultSet) proc.getObject(1);
while(rs.next()){
int empno=rs.getInt("empno");
String ename=rs.getString("ename");
String job=rs.getString("job");
int mgr=rs.getInt("mgr");
Date hiredate=rs.getDate("hiredate");
double sal=rs.getDouble("sal");
double comm=rs.getDouble("comm");
int deptno=rs.getInt("deptno");
//声明Emp对象
Emp emp=new Emp();
//将得到的值添加到对象中
emp.setEmpno(empno);
emp.setEname(ename);
emp.setJob(job);
emp.setMgr(mgr);
emp.setHiredate(hiredate);
emp.setSal(sal);
emp.setComm(comm);
emp.setDeptno(deptno);
//将对象添加到集合
emplist.add(emp);
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
this.closeResource();
if(proc!=null){
try {
proc.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return emplist;
}

以上看出,需要将输出的参数,和结果注册,输入的参数不要注册,

但输入参数需要设置占位符

三、执行函数

3.1 、函数功能为根据雇员id 返回姓名

CREATE OR REPLACE FUNCTION getename(v_empno NUMBER)
RETURN VARCHAR2
AS
v_ename VARCHAR2(20);
BEGIN
SELECT ename INTO v_ename FROM emp WHERE empno=v_empno;
RETURN v_ename;
END;
public void getenamefun(int empno){
//sql
String ename="";
String sql="{?=call getename(?)}";
CallableStatement fun=null;
getConnection();
try {
fun=conn.prepareCall(sql);
fun.setInt(2, empno);
fun.registerOutParameter(1, Types.VARCHAR);
fun.execute();
ename=fun.getString(1);
System.out.println(ename);
} catch (SQLException e) {
e.printStackTrace();
} }

其它的方法与过程一样,只是多了个返回值类型

原博客链接:http://www.cnblogs.com/liunanjava/p/4261242.html

【转】java调用存储过程和函数的更多相关文章

  1. java调用存储过程和函数

    以对表test进行增,删,改,查进行说明:1.新建表test create table TEST ( TID NUMBER not null, TNAME VARCHAR2(32), TCODE VA ...

  2. Java 调用存储过程、函数

     一.Java调用存储Oracle存储过程 测试用表: --创建用户表 create table USERINFO ( username ) not null, password ) not null ...

  3. JDBC第二篇--【PreparedStatment、批处理、处理二进制、自动主键、调用存储过程、函数】

    这是我JDBC的第一篇 http://blog.csdn.net/hon_3y/article/details/53535798 1.PreparedStatement对象 PreparedState ...

  4. JDBC【PreparedStatment、批处理、处理二进制、自动主键、调用存储过程、函数】

    1.PreparedStatement对象 PreparedStatement对象继承Statement对象,它比Statement对象更强大,使用起来更简单 Statement对象编译SQL语句时, ...

  5. JDBC(13)—JDBC调用存储过程和函数

    步骤: JDBC调用存储过程和函数 步骤: ①:通过Connection对象的prepareCall()方法创建一个CallableStatement对象的实例,在使用Connection对象的pre ...

  6. 转:EF调用存储过程、函数

    EF调用存储过程.函数 2014-04-02 09:12:20|  分类: ORM框架|举报|字号 订阅          一.ef4.1 codeFirst 修改表结构 增加字段等 EF code ...

  7. clob字段的值插入和查询N种方法【包括java调用存储过程传入clob参数】

    import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import jav ...

  8. MySQL学习笔记:调用存储过程或函数报1418错误

    问题 MySQL开启bin-log后,调用存储过程或者函数以及触发器时,会出现错误号为1418的错误: ERROR 1418 (HY000): This function has none of DE ...

  9. Oracle数据库基本操作 (五) —— 使用java调用存储过程

    一.环境准备 登录Oracle数据库scott账号,利用emp进行操作. 1.创建 proc_getyearsal 存储过程 -- 获取指定员工年薪 create or replace procedu ...

随机推荐

  1. alt+shift+j,添加日期、作者等

    在preference->Java->codestyle->codetemplates->commnets->type 可以编辑如: /** * @author ${us ...

  2. 2016大连网络赛 Sparse Graph

    Sparse Graph Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) P ...

  3. word2016怎么从第三页开始设置页码

    在Word中,默认为一节,每节的页码是连续的,若想在一个Word文档中,前2页不设页码,从第3页开始设置页码,必须插入分节符,使文档分成两节,这样就可以单独设置页码.操作步骤:1.将光标放在第4页的首 ...

  4. foreach的2个细节!

    人生不应该在同第一个地方摔第三次.... 1. foreach的时候一定要对要遍历的元素进行null判定. 2. foreach中不要对遍历的元素进行增删改操作(问题严重) 还有一个细节: 使用了的流 ...

  5. background系列属性

    1.background-color背景颜色属性 ①颜色表示方法 英语单词:red   blue   purple    skyblue. rgb:r代表红色   g代表绿色   b代表蓝色    也 ...

  6. docker固定IP地址重启不变

    docker固定IP地址重启不变 代码地址 https://github.com/lioncui/docker-static-ip 宿主机IP为  10.6.17.12 docker IP为 10.6 ...

  7. How to get HTML code of a WebElement in Selenium

    http://stackoverflow.com/questions/32234205/how-to-get-html-code-of-a-webelement-in-selenium WebElem ...

  8. 笔记:利用 Cocos2dx 3.2 与 Box2D制作一个跑酷游戏(上)

    最近写lua写得没有力气了,所以想让脑袋放松一下,刚好看到有人在用swift做游戏: Swift游戏实战-跑酷熊猫 于是脑子一短路,就想到了利用这些素材来做一个游戏. 本来不想记笔记的,但是由于选择物 ...

  9. (简单) POJ 3259 Wormholes,SPFA判断负环。

    Description While exploring his many farms, Farmer John has discovered a number of amazing wormholes ...

  10. 解决phpcms V9缩略图模糊的方法

    解决V9缩略图模糊/libs/classes/image.class.php注释掉else   imagecopyresized($thumbimg, $srcimg, 0, 0, $psrc_x,  ...