项目中用到了Java调用存储过程,趟过了几个坑,现分享一下常用的几种情形。下面的例子用的JdbcTemplate对持久层进行操作,有关JdbcTemplate的配置本文不再做详细说明,如不清楚,可参考本人另一篇博文SpringBoot使用JdbcTemplate多种方式介绍。
第一种情况:有普通返回值。
存储过程示例:
过程定义(获取学生信息):
PROCEDURE proc_get_student
(sno in VARCHAR2 --学号
,name in out VARCHAR2 --姓名
,age in out number --年龄
,classno in out VARCHAR2 --班级
);
实现代码:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.CallableStatementCreator;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import java.sql.*;
@Component
public class ProcedureDemo {
@Autowired
JdbcTemplate jdbcTemplate;
public void queryStudentInfo() {
jdbcTemplate.execute(
new CallableStatementCreator() {
@Override
public CallableStatement createCallableStatement(Connection con) throws SQLException {
String storedProc = "{call comm.proc_get_student(?,?,?,?)}";// 调用的sql
CallableStatement cs = con.prepareCall(storedProc);
cs.setString(1, "001");//设置输入参数-学号
cs.registerOutParameter(2, Types.VARCHAR);//输出参数
cs.registerOutParameter(3, Types.INTEGER);
cs.registerOutParameter(4, Types.VARCHAR);
return cs;
}
}, new CallableStatementCallback() {
@Override
public Object doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
cs.execute();
String name = cs.getString(2);
int age = cs.getInt(3);
String classno = cs.getString(4);
return null;
}
});
}
}
第二种情况:有数据集返回。
存储过程示例:
过程定义(获取一个班级学生信息):
PROCEDURE proc_get_students
(classno in VARCHAR2 --班级
,classname in out VARCHAR2 --班级名称
,cur_studentinfo in out returncursor --学生信息结果集
);
实现代码:
import oracle.jdbc.OracleTypes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.CallableStatementCreator;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import java.sql.*;
@Component
public class ProcedureDemo {
@Autowired
JdbcTemplate jdbcTemplate;
public void queryStudentInfos() {
jdbcTemplate.execute(
new CallableStatementCreator() {
@Override
public CallableStatement createCallableStatement(Connection con) throws SQLException {
String storedProc = "{call comm.proc_get_students(?,?,?)}";// 调用的sql
CallableStatement cs = con.prepareCall(storedProc);
cs.setString(1, "01");//班级号
cs.registerOutParameter(2, Types.VARCHAR);
cs.registerOutParameter(3, OracleTypes.CURSOR);//输出参数游标类型
return cs;
}
}, new CallableStatementCallback() {
@Override
public Object doInCallableStatement(CallableStatement cs) throws SQLException,DataAccessException {
cs.execute();
System.out.println(cs.getString(2));
ResultSet rs = (ResultSet) cs.getObject(3);// 获取游标一行的值
while (rs.next()) {//打印每行的返回值
System.out.println(rs.getString("sno"));
System.out.println(rs.getString("name"));
System.out.println(rs.getInt("age"));
}
rs.close();
return null;
}
});
}
}
这种情况的难点在于输出参数为游标类型数据集,设置参数类型的时候为OracleTypes.CURSOR,依赖的jar包为ojdbc14-18.3.0.0.jar,对应的maven依赖:
com.oracle
ojdbc14
18.3.0.0
第三种情况:输出参数为clob类型。
存储过程示例:
过程定义(获取学生成绩信息):
PROCEDURE proc_get_student_performance
(sno in VARCHAR2 --学号
,student_return in out clob --学生成绩报文,json字符串格式
);
实现代码:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.CallableStatementCreator;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.StringWriter;
import java.sql.*;
@Component
public class ProcedureDemo {
@Autowired
JdbcTemplate jdbcTemplate;
public void queryStudentPerformance() {
jdbcTemplate.execute(
new CallableStatementCreator() {
@Override
public CallableStatement createCallableStatement(Connection con) throws SQLException {
String storedProc = "{call comm.proc_get_student_performance(?,?)}";// 调用的sql
CallableStatement cs = con.prepareCall(storedProc);
cs.setString(1, "001");
cs.registerOutParameter(2, Types.CLOB);//设置出参为clob类型
return cs;
}
}, new CallableStatementCallback() {
@Override
public Object doInCallableStatement(CallableStatement cs) throws SQLException,DataAccessException {
cs.execute();
try {
Clob student_return = cs.getClob(2);
BufferedReader in = new BufferedReader(student_return.getCharacterStream());
StringWriter out = new StringWriter();
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
String studentJsonStr = out.toString();//获取到json字符串,后面的解析省略
System.out.println(studentJsonStr);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
});
}
}
第四种情况:输入参数为clob类型。
存储过程示例:
过程定义(保存学生成绩信息):
PROCEDURE proc_save_student_performance
(sno in VARCHAR2 --学号
,student_save in clob --学生成绩报文,json字符串格式
);
实现代码:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.CallableStatementCreator;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import java.sql.*;
@Component
public class ProcedureDemo {
@Autowired
JdbcTemplate jdbcTemplate;
public void saveStudentPerformance(String performanceJsonStr) {
jdbcTemplate.execute(
new CallableStatementCreator() {
@Override
public CallableStatement createCallableStatement(Connection con) throws SQLException {
Clob performanceClob = new javax.sql.rowset.serial.SerialClob(performanceJsonStr.toCharArray());
String storedProc = "{call comm.proc_save_student_performance(?,?)}";// 调用的sql
CallableStatement cs = con.prepareCall(storedProc);
cs.setString(1, "001");
cs.setClob(2, performanceClob);
return cs;
}
}, new CallableStatementCallback() {
@Override
public Object doInCallableStatement(CallableStatement cs) throws SQLException,DataAccessException {
cs.execute();
return null;
}
});
}
}
以上为常遇到的几种情况,不足之处敬请斧正。