请问java该如何使用 CallableStatement 接口来完成存储过程的调用, 要能得到记录集, 还有输出参数值. 郁闷啊.
我在实践中确实得到了 ResultSet , 但是, 当调用得到的 ResultSet 的 next() 方法时就报这个错误:
[Microsoft][SQLServer 2000 Driver for JDBC]Object has been closed
看了一些网上的有关oracle文章,通过将结果集注册 (registerOutParameter)为 OracleTypes.CURSOR 类型,能得以实现, 还有的将结果集注册为 java.sql.Types.OTHER 也可以. 最后通过 (ResultSet)CallableStatement.getObject(1) 得到ResultSet . 但我在 mssql server 下测试时, mssql server 的 jdbc driver 总是说不支持这样的数据类型.
狂郁闷. 谁有这方面经验能给俺分享分享吗 小弟先在此谢过大家了
8 个解决方案
#1
返回CURSOR类型的,我见过有人用以下方法
ResultSet rs = null;
int updateCount = -1;
flag = cs.execute();
do{
updateCount = cs.getUpdateCount();
if(updateCount != -1){//说明当前行是一个更新计数
//处理.
cs.getMoreResults();
continue;//已经是更新计数了,处理完成后应该移动到下一行
//不再判断是否是ResultSet
}
rs = cs.getResultSet();
if(rs != null){//如果到了这里,说明updateCount == -1
//处理rs
cs.getMoreResults();
continue;
//是结果集,处理完成后应该移动到下一行
}
//如果到了这里,说明updateCount == -1 && rs == null,什么也没的了
}while(!(updateCount == -1 && rs == null));
------------------------------------------------
我是一直用oracler的,用(ResultSet)CallableStatement.getObject(1)没问题
手头没用SQLSERVER,上面程序供你参考
ResultSet rs = null;
int updateCount = -1;
flag = cs.execute();
do{
updateCount = cs.getUpdateCount();
if(updateCount != -1){//说明当前行是一个更新计数
//处理.
cs.getMoreResults();
continue;//已经是更新计数了,处理完成后应该移动到下一行
//不再判断是否是ResultSet
}
rs = cs.getResultSet();
if(rs != null){//如果到了这里,说明updateCount == -1
//处理rs
cs.getMoreResults();
continue;
//是结果集,处理完成后应该移动到下一行
}
//如果到了这里,说明updateCount == -1 && rs == null,什么也没的了
}while(!(updateCount == -1 && rs == null));
------------------------------------------------
我是一直用oracler的,用(ResultSet)CallableStatement.getObject(1)没问题
手头没用SQLSERVER,上面程序供你参考
#2
试下, 多谢楼上兄弟
#3
还是不行, 明明拿到了 ResultSet , 就是说这个错 ojbect has been closed
而且通过stmt.getMetaData 方法, 查看到 ResultSet 的metadata 也确是我想要的结果. 为什么就不给我呢????
而且通过stmt.getMetaData 方法, 查看到 ResultSet 的metadata 也确是我想要的结果. 为什么就不给我呢????
#4
声明
private CallableStatement sqlSend;
sqlSend = remoteConn.prepareCall("{ call " + dataUser + ".proGroupsms1(?,?,?,?,?,?,?,?,?) }");
执行
try{
sqlSend.setString(1,sendSms.sp_num);
sqlSend.setString(2,sendSms.dst_num);
sqlSend.setString(3,sendSms.busi_code);
sqlSend.setByte(4,sendSms.msg_code);
sqlSend.setString(5,sendSms.content);
sqlSend.setString(6,sendSms.reserve);
sqlSend.registerOutParameter(7,java.sql.Types.INTEGER);
sqlSend.setString(8,NewClient.spNum);
sqlSend.setString(9,sendSms.msgid);
sqlSend.executeUpdate();
remoteConn.commit();
errSms = new ErrorSMS();
errSms.msg_id = sendSms.msg_id;
errSms.err_code = (byte)sqlSend.getInt(7);
if (NewClient.in_debug == 1)
System.out.println("[RemoteDBThread]Put a RetCode:" + errSms.err_code);
errSms = (ErrorSMS)merrQueue.writeNoWait(errSms);
sendSms = (SendSMS)msendQueue.read(sendSms);
}catch(Exception e){
e.printStackTrace();
System.out.println("[RemoteDBThread]发送短信过程出错,跳过......");
remoteConn.rollback();
sendSms = (SendSMS)msendQueue.read(sendSms);
}
#5
声明
private CallableStatement sqlSend;
sqlSend = remoteConn.prepareCall("{ call " + dataUser + ".proGroupsms1(?,?,?,?,?,?,?,?,?) }");
执行
try{
sqlSend.setString(1,sendSms.sp_num);
sqlSend.setString(2,sendSms.dst_num);
sqlSend.setString(3,sendSms.busi_code);
sqlSend.setByte(4,sendSms.msg_code);
sqlSend.setString(5,sendSms.content);
sqlSend.setString(6,sendSms.reserve);
sqlSend.registerOutParameter(7,java.sql.Types.INTEGER);
sqlSend.setString(8,NewClient.spNum);
sqlSend.setString(9,sendSms.msgid);
sqlSend.executeUpdate();
remoteConn.commit();
errSms = new ErrorSMS();
errSms.msg_id = sendSms.msg_id;
errSms.err_code = (byte)sqlSend.getInt(7);
if (NewClient.in_debug == 1)
System.out.println("[RemoteDBThread]Put a RetCode:" + errSms.err_code);
errSms = (ErrorSMS)merrQueue.writeNoWait(errSms);
sendSms = (SendSMS)msendQueue.read(sendSms);
}catch(Exception e){
e.printStackTrace();
System.out.println("[RemoteDBThread]发送短信过程出错,跳过......");
remoteConn.rollback();
sendSms = (SendSMS)msendQueue.read(sendSms);
}
这是JAVA调用ORACLE存储过程非常好用安全的程序段,不知道是不是有用!
private CallableStatement sqlSend;
sqlSend = remoteConn.prepareCall("{ call " + dataUser + ".proGroupsms1(?,?,?,?,?,?,?,?,?) }");
执行
try{
sqlSend.setString(1,sendSms.sp_num);
sqlSend.setString(2,sendSms.dst_num);
sqlSend.setString(3,sendSms.busi_code);
sqlSend.setByte(4,sendSms.msg_code);
sqlSend.setString(5,sendSms.content);
sqlSend.setString(6,sendSms.reserve);
sqlSend.registerOutParameter(7,java.sql.Types.INTEGER);
sqlSend.setString(8,NewClient.spNum);
sqlSend.setString(9,sendSms.msgid);
sqlSend.executeUpdate();
remoteConn.commit();
errSms = new ErrorSMS();
errSms.msg_id = sendSms.msg_id;
errSms.err_code = (byte)sqlSend.getInt(7);
if (NewClient.in_debug == 1)
System.out.println("[RemoteDBThread]Put a RetCode:" + errSms.err_code);
errSms = (ErrorSMS)merrQueue.writeNoWait(errSms);
sendSms = (SendSMS)msendQueue.read(sendSms);
}catch(Exception e){
e.printStackTrace();
System.out.println("[RemoteDBThread]发送短信过程出错,跳过......");
remoteConn.rollback();
sendSms = (SendSMS)msendQueue.read(sendSms);
}
这是JAVA调用ORACLE存储过程非常好用安全的程序段,不知道是不是有用!
#6
我试了一下,上面的程序是可用的,只是有个小问题
以下是我的测试程序:
public class sqltest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try{
Connection conn;
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conn=DriverManager.getConnection("jdbc:odbc:Driver={SQL Server};Server=vpc98;uid=sa;pwd=;Database=master");
String sql="";
Statement st=conn.createStatement();
ResultSet rs;
/* sql="select * from test";
rs=st.executeQuery(sql);
while (rs.next())
{
String id=rs.getString("postcode");
System.out.println(id);
}
if (rs!=null) rs.close();
*/
CallableStatement cs = conn.prepareCall("dbo.sp_tables");
rs = null;
int updateCount = -1;
boolean flag = cs.execute();
do{
updateCount = cs.getUpdateCount();
if(updateCount != -1){//说明当前行是一个更新计数
//处理.
cs.getMoreResults();
System.out.println(updateCount);
continue;//已经是更新计数了,处理完成后应该移动到下一行
//不再判断是否是ResultSet
}
rs = cs.getResultSet();
if(rs != null){//如果到了这里,说明updateCount == -1
//处理rs
System.out.println("ok");
while (rs.next())
{
String id=rs.getString("table_name");
System.out.println(id);
}
rs.close();
rs = null;
//cs.getMoreResults();
continue;
//是结果集,处理完成后应该移动到下一行
}
//如果到了这里,说明updateCount == -1 && rs == null,什么也没的了
}while(!(updateCount == -1 && rs == null));
if (st!=null)st.close();
if (conn!=null) conn.close();
}
catch(Exception e){
System.out.println(e.toString());
}
}
}
我是以系统的sp_tables过程作为测试的,它的返回就是一个记录集
不过我不知如果是在参数中返回是否可以(sp_tables是在结果中返回的),因为我对SQL Server不熟
楼主可再试一下你的存储过程是否可用
另外,楼上的是用oracle,我上面提过oracle用(ResultSet)CallableStatement.getObject(1)是肯定可以的,我就这样用过
以下是我的测试程序:
public class sqltest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try{
Connection conn;
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conn=DriverManager.getConnection("jdbc:odbc:Driver={SQL Server};Server=vpc98;uid=sa;pwd=;Database=master");
String sql="";
Statement st=conn.createStatement();
ResultSet rs;
/* sql="select * from test";
rs=st.executeQuery(sql);
while (rs.next())
{
String id=rs.getString("postcode");
System.out.println(id);
}
if (rs!=null) rs.close();
*/
CallableStatement cs = conn.prepareCall("dbo.sp_tables");
rs = null;
int updateCount = -1;
boolean flag = cs.execute();
do{
updateCount = cs.getUpdateCount();
if(updateCount != -1){//说明当前行是一个更新计数
//处理.
cs.getMoreResults();
System.out.println(updateCount);
continue;//已经是更新计数了,处理完成后应该移动到下一行
//不再判断是否是ResultSet
}
rs = cs.getResultSet();
if(rs != null){//如果到了这里,说明updateCount == -1
//处理rs
System.out.println("ok");
while (rs.next())
{
String id=rs.getString("table_name");
System.out.println(id);
}
rs.close();
rs = null;
//cs.getMoreResults();
continue;
//是结果集,处理完成后应该移动到下一行
}
//如果到了这里,说明updateCount == -1 && rs == null,什么也没的了
}while(!(updateCount == -1 && rs == null));
if (st!=null)st.close();
if (conn!=null) conn.close();
}
catch(Exception e){
System.out.println(e.toString());
}
}
}
我是以系统的sp_tables过程作为测试的,它的返回就是一个记录集
不过我不知如果是在参数中返回是否可以(sp_tables是在结果中返回的),因为我对SQL Server不熟
楼主可再试一下你的存储过程是否可用
另外,楼上的是用oracle,我上面提过oracle用(ResultSet)CallableStatement.getObject(1)是肯定可以的,我就这样用过
#7
谢谢楼上热心的朋友.
我已经找到问题的答案了.
如果存储过程返回结果集, 并且同时还有输出参数的话, 在java里面应该使用完结果集, 再使用getXXX(parameterIndex)这样的方法获取输出参数, 因为每当使用getXXX系列方法获取输出参数时,jdbc会自动关闭结果集......残念呀......在jdk文档里关于CallableStatement接口的说明有这样一段话,再明白不过了:For maximum portability, a call's ResultSet objects and update counts should be processed prior to getting the values of output parameters.
谢谢上面热心参与的朋友,本贴保留至今晚(2005-09-22),到时将结贴散分.
我已经找到问题的答案了.
如果存储过程返回结果集, 并且同时还有输出参数的话, 在java里面应该使用完结果集, 再使用getXXX(parameterIndex)这样的方法获取输出参数, 因为每当使用getXXX系列方法获取输出参数时,jdbc会自动关闭结果集......残念呀......在jdk文档里关于CallableStatement接口的说明有这样一段话,再明白不过了:For maximum portability, a call's ResultSet objects and update counts should be processed prior to getting the values of output parameters.
谢谢上面热心参与的朋友,本贴保留至今晚(2005-09-22),到时将结贴散分.
#8
学习
#1
返回CURSOR类型的,我见过有人用以下方法
ResultSet rs = null;
int updateCount = -1;
flag = cs.execute();
do{
updateCount = cs.getUpdateCount();
if(updateCount != -1){//说明当前行是一个更新计数
//处理.
cs.getMoreResults();
continue;//已经是更新计数了,处理完成后应该移动到下一行
//不再判断是否是ResultSet
}
rs = cs.getResultSet();
if(rs != null){//如果到了这里,说明updateCount == -1
//处理rs
cs.getMoreResults();
continue;
//是结果集,处理完成后应该移动到下一行
}
//如果到了这里,说明updateCount == -1 && rs == null,什么也没的了
}while(!(updateCount == -1 && rs == null));
------------------------------------------------
我是一直用oracler的,用(ResultSet)CallableStatement.getObject(1)没问题
手头没用SQLSERVER,上面程序供你参考
ResultSet rs = null;
int updateCount = -1;
flag = cs.execute();
do{
updateCount = cs.getUpdateCount();
if(updateCount != -1){//说明当前行是一个更新计数
//处理.
cs.getMoreResults();
continue;//已经是更新计数了,处理完成后应该移动到下一行
//不再判断是否是ResultSet
}
rs = cs.getResultSet();
if(rs != null){//如果到了这里,说明updateCount == -1
//处理rs
cs.getMoreResults();
continue;
//是结果集,处理完成后应该移动到下一行
}
//如果到了这里,说明updateCount == -1 && rs == null,什么也没的了
}while(!(updateCount == -1 && rs == null));
------------------------------------------------
我是一直用oracler的,用(ResultSet)CallableStatement.getObject(1)没问题
手头没用SQLSERVER,上面程序供你参考
#2
试下, 多谢楼上兄弟
#3
还是不行, 明明拿到了 ResultSet , 就是说这个错 ojbect has been closed
而且通过stmt.getMetaData 方法, 查看到 ResultSet 的metadata 也确是我想要的结果. 为什么就不给我呢????
而且通过stmt.getMetaData 方法, 查看到 ResultSet 的metadata 也确是我想要的结果. 为什么就不给我呢????
#4
声明
private CallableStatement sqlSend;
sqlSend = remoteConn.prepareCall("{ call " + dataUser + ".proGroupsms1(?,?,?,?,?,?,?,?,?) }");
执行
try{
sqlSend.setString(1,sendSms.sp_num);
sqlSend.setString(2,sendSms.dst_num);
sqlSend.setString(3,sendSms.busi_code);
sqlSend.setByte(4,sendSms.msg_code);
sqlSend.setString(5,sendSms.content);
sqlSend.setString(6,sendSms.reserve);
sqlSend.registerOutParameter(7,java.sql.Types.INTEGER);
sqlSend.setString(8,NewClient.spNum);
sqlSend.setString(9,sendSms.msgid);
sqlSend.executeUpdate();
remoteConn.commit();
errSms = new ErrorSMS();
errSms.msg_id = sendSms.msg_id;
errSms.err_code = (byte)sqlSend.getInt(7);
if (NewClient.in_debug == 1)
System.out.println("[RemoteDBThread]Put a RetCode:" + errSms.err_code);
errSms = (ErrorSMS)merrQueue.writeNoWait(errSms);
sendSms = (SendSMS)msendQueue.read(sendSms);
}catch(Exception e){
e.printStackTrace();
System.out.println("[RemoteDBThread]发送短信过程出错,跳过......");
remoteConn.rollback();
sendSms = (SendSMS)msendQueue.read(sendSms);
}
#5
声明
private CallableStatement sqlSend;
sqlSend = remoteConn.prepareCall("{ call " + dataUser + ".proGroupsms1(?,?,?,?,?,?,?,?,?) }");
执行
try{
sqlSend.setString(1,sendSms.sp_num);
sqlSend.setString(2,sendSms.dst_num);
sqlSend.setString(3,sendSms.busi_code);
sqlSend.setByte(4,sendSms.msg_code);
sqlSend.setString(5,sendSms.content);
sqlSend.setString(6,sendSms.reserve);
sqlSend.registerOutParameter(7,java.sql.Types.INTEGER);
sqlSend.setString(8,NewClient.spNum);
sqlSend.setString(9,sendSms.msgid);
sqlSend.executeUpdate();
remoteConn.commit();
errSms = new ErrorSMS();
errSms.msg_id = sendSms.msg_id;
errSms.err_code = (byte)sqlSend.getInt(7);
if (NewClient.in_debug == 1)
System.out.println("[RemoteDBThread]Put a RetCode:" + errSms.err_code);
errSms = (ErrorSMS)merrQueue.writeNoWait(errSms);
sendSms = (SendSMS)msendQueue.read(sendSms);
}catch(Exception e){
e.printStackTrace();
System.out.println("[RemoteDBThread]发送短信过程出错,跳过......");
remoteConn.rollback();
sendSms = (SendSMS)msendQueue.read(sendSms);
}
这是JAVA调用ORACLE存储过程非常好用安全的程序段,不知道是不是有用!
private CallableStatement sqlSend;
sqlSend = remoteConn.prepareCall("{ call " + dataUser + ".proGroupsms1(?,?,?,?,?,?,?,?,?) }");
执行
try{
sqlSend.setString(1,sendSms.sp_num);
sqlSend.setString(2,sendSms.dst_num);
sqlSend.setString(3,sendSms.busi_code);
sqlSend.setByte(4,sendSms.msg_code);
sqlSend.setString(5,sendSms.content);
sqlSend.setString(6,sendSms.reserve);
sqlSend.registerOutParameter(7,java.sql.Types.INTEGER);
sqlSend.setString(8,NewClient.spNum);
sqlSend.setString(9,sendSms.msgid);
sqlSend.executeUpdate();
remoteConn.commit();
errSms = new ErrorSMS();
errSms.msg_id = sendSms.msg_id;
errSms.err_code = (byte)sqlSend.getInt(7);
if (NewClient.in_debug == 1)
System.out.println("[RemoteDBThread]Put a RetCode:" + errSms.err_code);
errSms = (ErrorSMS)merrQueue.writeNoWait(errSms);
sendSms = (SendSMS)msendQueue.read(sendSms);
}catch(Exception e){
e.printStackTrace();
System.out.println("[RemoteDBThread]发送短信过程出错,跳过......");
remoteConn.rollback();
sendSms = (SendSMS)msendQueue.read(sendSms);
}
这是JAVA调用ORACLE存储过程非常好用安全的程序段,不知道是不是有用!
#6
我试了一下,上面的程序是可用的,只是有个小问题
以下是我的测试程序:
public class sqltest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try{
Connection conn;
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conn=DriverManager.getConnection("jdbc:odbc:Driver={SQL Server};Server=vpc98;uid=sa;pwd=;Database=master");
String sql="";
Statement st=conn.createStatement();
ResultSet rs;
/* sql="select * from test";
rs=st.executeQuery(sql);
while (rs.next())
{
String id=rs.getString("postcode");
System.out.println(id);
}
if (rs!=null) rs.close();
*/
CallableStatement cs = conn.prepareCall("dbo.sp_tables");
rs = null;
int updateCount = -1;
boolean flag = cs.execute();
do{
updateCount = cs.getUpdateCount();
if(updateCount != -1){//说明当前行是一个更新计数
//处理.
cs.getMoreResults();
System.out.println(updateCount);
continue;//已经是更新计数了,处理完成后应该移动到下一行
//不再判断是否是ResultSet
}
rs = cs.getResultSet();
if(rs != null){//如果到了这里,说明updateCount == -1
//处理rs
System.out.println("ok");
while (rs.next())
{
String id=rs.getString("table_name");
System.out.println(id);
}
rs.close();
rs = null;
//cs.getMoreResults();
continue;
//是结果集,处理完成后应该移动到下一行
}
//如果到了这里,说明updateCount == -1 && rs == null,什么也没的了
}while(!(updateCount == -1 && rs == null));
if (st!=null)st.close();
if (conn!=null) conn.close();
}
catch(Exception e){
System.out.println(e.toString());
}
}
}
我是以系统的sp_tables过程作为测试的,它的返回就是一个记录集
不过我不知如果是在参数中返回是否可以(sp_tables是在结果中返回的),因为我对SQL Server不熟
楼主可再试一下你的存储过程是否可用
另外,楼上的是用oracle,我上面提过oracle用(ResultSet)CallableStatement.getObject(1)是肯定可以的,我就这样用过
以下是我的测试程序:
public class sqltest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try{
Connection conn;
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conn=DriverManager.getConnection("jdbc:odbc:Driver={SQL Server};Server=vpc98;uid=sa;pwd=;Database=master");
String sql="";
Statement st=conn.createStatement();
ResultSet rs;
/* sql="select * from test";
rs=st.executeQuery(sql);
while (rs.next())
{
String id=rs.getString("postcode");
System.out.println(id);
}
if (rs!=null) rs.close();
*/
CallableStatement cs = conn.prepareCall("dbo.sp_tables");
rs = null;
int updateCount = -1;
boolean flag = cs.execute();
do{
updateCount = cs.getUpdateCount();
if(updateCount != -1){//说明当前行是一个更新计数
//处理.
cs.getMoreResults();
System.out.println(updateCount);
continue;//已经是更新计数了,处理完成后应该移动到下一行
//不再判断是否是ResultSet
}
rs = cs.getResultSet();
if(rs != null){//如果到了这里,说明updateCount == -1
//处理rs
System.out.println("ok");
while (rs.next())
{
String id=rs.getString("table_name");
System.out.println(id);
}
rs.close();
rs = null;
//cs.getMoreResults();
continue;
//是结果集,处理完成后应该移动到下一行
}
//如果到了这里,说明updateCount == -1 && rs == null,什么也没的了
}while(!(updateCount == -1 && rs == null));
if (st!=null)st.close();
if (conn!=null) conn.close();
}
catch(Exception e){
System.out.println(e.toString());
}
}
}
我是以系统的sp_tables过程作为测试的,它的返回就是一个记录集
不过我不知如果是在参数中返回是否可以(sp_tables是在结果中返回的),因为我对SQL Server不熟
楼主可再试一下你的存储过程是否可用
另外,楼上的是用oracle,我上面提过oracle用(ResultSet)CallableStatement.getObject(1)是肯定可以的,我就这样用过
#7
谢谢楼上热心的朋友.
我已经找到问题的答案了.
如果存储过程返回结果集, 并且同时还有输出参数的话, 在java里面应该使用完结果集, 再使用getXXX(parameterIndex)这样的方法获取输出参数, 因为每当使用getXXX系列方法获取输出参数时,jdbc会自动关闭结果集......残念呀......在jdk文档里关于CallableStatement接口的说明有这样一段话,再明白不过了:For maximum portability, a call's ResultSet objects and update counts should be processed prior to getting the values of output parameters.
谢谢上面热心参与的朋友,本贴保留至今晚(2005-09-22),到时将结贴散分.
我已经找到问题的答案了.
如果存储过程返回结果集, 并且同时还有输出参数的话, 在java里面应该使用完结果集, 再使用getXXX(parameterIndex)这样的方法获取输出参数, 因为每当使用getXXX系列方法获取输出参数时,jdbc会自动关闭结果集......残念呀......在jdk文档里关于CallableStatement接口的说明有这样一段话,再明白不过了:For maximum portability, a call's ResultSet objects and update counts should be processed prior to getting the values of output parameters.
谢谢上面热心参与的朋友,本贴保留至今晚(2005-09-22),到时将结贴散分.
#8
学习