一:先看几个概念:
首先,自己参考了几篇文章,写的很不错,自己也借鉴一下,然后会在最后贴出自己在项目中使用到的存储过程,已经实现过程,大家可以做个对比,实现方法不同。http://www.cnblogs.com/liunanjava/p/4261242.html
过程和函数,它们被编译后保存在数据库中,称为持久性存储模块(Persistent Stored Module,PSM),可以反复调用,运行速度快。不同之处是函数必须指定返回类型。
Java调用结构:
存储过程:{call
函数:{?= call
如果要调用存储过程,则使用第一种语法,就是开头不带问号的语法,call 后面是过程名,
如果没有参数,可以省略小括号。
如果要调用函数,则使用第二种语法,开头带有一个问号加等号,实际上这个问号就是一个占位符,这个问号总是调用函数的第一个占位符。其它部分与过程的语法相同。
二、CallableStatement 执行存储过程:
package com.pb.emp.dao; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import com.pb.emp.untily.ConfigManager; 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) { // TODO Auto-generated catch block e.printStackTrace(); return false; } catch (SQLException e) { // TODO Auto-generated catch block 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 --查询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) { // TODO Auto-generated catch block e.printStackTrace(); } return totalCount; }
//执行带参带返回值的存储过程 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) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ this.closeResource(); if(proc!=null){ try { proc.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } return totalCount; } --查询员工所有信息 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
以上看出,需要将输出的参数,和结果注册,输入的参数不要注册, 但输入参数需要设置占位符。 三、执行函数。 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) { // TODO Auto-generated catch block e.printStackTrace(); } } ------------------------------------------------------------------ 四:接下来说下自己项目中的,直接看代码。 创建储存过程的代码基本一样,只是Java调用存储过程的时候,跟上边调用的方法不同,大家可以自行理解: 4.1:更新订单状态,返回状态值 DELIMITER $$ -------------先定义语句的结束符号 USE `zhangzi_tester`$$ DROP PROCEDURE IF EXISTS `pay_orderState`$$ CREATE PROCEDURE `pay_orderState`( IN serNumbner VARCHAR (32), IN itemId VARCHAR (32), IN captions INT, IN cfcaPayTime VARCHAR(32), IN payDate VARCHAR(30), OUT state VARCHAR (2)) BEGIN DECLARE maxMoney INT DEFAULT 0; DECLARE countMoney INT DEFAULT 0; DECLARE caps INT DEFAULT 0; START TRANSACTION;-- 配置事务 SELECT IFNULL(max_finance_money,0) INTO maxMoney FROM t_item_info WHERE id = itemId; SELECT IFNULL(SUM(capital),0) INTO countMoney FROM t_order_info WHERE fk_item_id = itemId AND pay_status = '01'; IF maxMoney >= captions+countMoney THEN -- 判断有没有超募 IF maxMoney = countMoney+captions THEN UPDATE t_item_info SET full_flag='01' WHERE id= itemId; END IF; UPDATE t_order_info SET pay_status = '01',order_complete_date = cfcaPayTime, pay_date= payDate WHERE serial_number = serNumbner; -- 没有超募 SET state ='1'; -- 未超募 返回1 ELSE UPDATE t_order_info SET pay_status = '03',order_complete_date = cfcaPayTime, pay_date= payDate WHERE serial_number = serNumbner; -- 没有超募 SET state ='3'; -- 已超募 返回3 END IF; COMMIT; -- 事务结束提交 END$$ DELIMITER ;---改成默认的分号; 4.2:Java调用存储过程代码 /* * 订单支付完成调用存储过程接口,修改订单支付状态 */ @SuppressWarnings("unchecked") public String orderState(final String serNumbner,final String itemId,final int captions,final String bankNotificationTime){ String param2Value=null; try{ param2Value = (String)jdbc.execute( new CallableStatementCreator() { public CallableStatement createCallableStatement(Connection con) throws SQLException { String storedProc = "{call pay_orderState(?,?,?,?,?,?)}";// 调用的sql CallableStatement cs = con.prepareCall(storedProc); cs.setString(1, serNumbner); cs.setString(2, itemId); cs.setInt(3, captions); cs.setString(4, bankNotificationTime); cs.setString(5,DateTimeUtils.getNowTime()); cs.registerOutParameter(6, Types.VARCHAR); return cs; } }, new CallableStatementCallback() { public Object doInCallableStatement(CallableStatement cs) throws SQLException,DataAccessException{ cs.execute(); return cs.getString(6);// 获取输出参数的值 } }); }catch(Exception ex){ throw new RuntimeException(ex); } return param2Value; } 4.3:再附上两段代码,有关Java调用储存过程的 @Resource(name = "jdbcTemplate") private JdbcTemplate jdbc; 4.4:最后一张图片--mysql执行储存过程
2.2、执行不带参但是有返回值的存储过程
下面建立存储过程
2.3、执行带参带返回值的存储过程
2.4、执行返回值为游标的存储过程
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;
其它的方法与过程一样,只是多了个返回值类型。