Java 未为存储过程定义参数@x。。。使用MS_SQL JDBC

Java 未为存储过程定义参数@x。。。使用MS_SQL JDBC,java,sql-server,stored-procedures,jdbc,mssql-jdbc,Java,Sql Server,Stored Procedures,Jdbc,Mssql Jdbc,我正在尝试在以下方法中使用SQL Server JDBC执行存储过程: //Connection connection, String sp_name, Map<String, Object>params input to the method DatabaseMetaData dbMetaData = connection.getMetaData(); HashMap<String, Integer> paramInfo = new HashMap<String,

我正在尝试在以下方法中使用SQL Server JDBC执行存储过程:

//Connection connection, String sp_name, Map<String, Object>params input to the method
DatabaseMetaData dbMetaData = connection.getMetaData();
HashMap<String, Integer> paramInfo = new HashMap<String, Integer>();
if (dbMetaData != null)
{
        ResultSet rs = dbMetaData.getProcedureColumns (null, null, sp_name.toUpperCase(), "%");
        while (rs.next())
            paramInfo.put(rs.getString(4), rs.getInt(6));
        rs.close();
}
String call = "{ call " + sp_name + " ( ";
for (int i = 0; i < paramInfo.size(); i ++)
    call += "?,";
if (paramInfo.size() > 0)
    call = call.substring(0, call.length() - 1);
call += " ) }";
CallableStatement st = connection.prepareCall (call);
for (String paramName: paramInfo.keySet()){
    int paramType = paramInfo.get(paramName);
    System.out.println("paramName="+paramName);
    System.out.println("paramTYpe="+paramType);
    Object paramVal = params.get(paramName);
    st.setInt(paramName, Integer.parseInt(((String)paramVal))); //All stored proc parameters are of type int
}
//连接,字符串sp_name,方法的Mapparams输入
DatabaseMetaData dbMetaData=connection.getMetaData();
HashMap paramInfo=新HashMap();
if(dbMetaData!=null)
{
ResultSet rs=dbMetaData.getProcedureClumns(null,null,sp_name.toUpperCase(),“%”;
while(rs.next())
paramInfo.put(rs.getString(4),rs.getInt(6));
rs.close();
}
String call=“{call”+sp_name+”(“;
对于(int i=0;i0)
call=call.substring(0,call.length()-1);
调用+=”)}”;
CallableStatement st=connection.prepareCall(调用);
对于(字符串paramName:paramInfo.keySet()){
int paramType=paramInfo.get(paramName);
System.out.println(“paramName=“+paramName”);
System.out.println(“paramTYpe=“+paramTYpe”);
Object paramVal=params.get(paramName);
st.setInt(paramName,Integer.parseInt(((String)paramVal));//所有存储的过程参数都是int类型
}
假设存储过程名称为
ABC
,参数为
@a
。 现在
DatabaseMetaData
返回列名
@a
,但设置
st.setInt(“@a”,0)
返回以下错误:

com.microsoft.sqlserver.jdbc.SQLServerException:未为存储过程ABC定义参数@a

相反,我尝试了这个:
st.setInt(“a”,0)
,它执行得非常完美

现在的问题是我必须动态设置参数,因为我有太多的存储过程和太多的参数,但是jdbc给出了错误

编辑1:

正如在一个答案中指出的,我的问题与:,重复,我想解释一下,这里的问题不是命名参数或位置参数,而是JDBC没有正确处理SQL server参数本身,或者我在调用它时出错。

更新2017-10-07:已接受,因此,这应该不再是版本和更高版本的问题


是的,不幸的是,对于mssql jdbc,
DatabaseMetaData#getProcedureColumns
返回的参数名与
CallableStatement#setInt
等接受的名称不匹配。。如果你认为它是一个bug,那么你应该创建一个,也许它将被固定在将来的版本中。 然而,与此同时,你只需要解决这个问题。所以,不是像这样的代码

ResultSet rs=connection.getMetaData().getprocedureclumns(null,“dbo”,“MenuPlanner”,null);
while(rs.next()){
if(rs.getShort(“COLUMN_TYPE”)==DatabaseMetaData.procedureclumnin){
字符串inParamName=rs.getString(“列名称”);
System.out.println(inParamName);
}
}
。。。这就产生了

@person
@食物
。。。您需要使用这样的代码

布尔ISMSQLJDBC=connection.getClass().getName().equals(
“com.microsoft.sqlserver.jdbc.SQLServerConnection”);
ResultSet rs=connection.getMetaData().getProcedureClumns(null,“dbo”,“MenuPlanner”,null);
while(rs.next()){
if(rs.getShort(“COLUMN_TYPE”)==DatabaseMetaData.procedureclumnin){
字符串inParamName=rs.getString(“列名称”);
if(isMssqlJdbc&&inParamName.startsWith(“@”)){
inParamName=inParamName.substring(1,inParamName.length());
}
System.out.println(inParamName);
}
}
。。。这就产生了

人
食物

不确定我是否正确理解您的意思,但为什么我可以(t您是否动态剥离了
@
?可能重复的@ScaryWombat?我需要一些既能与mysql和sql server一起工作,又能与其他服务器一起工作的东西,而无需进行具体更改,因为我希望JDBC能够处理它。@Bejasc
CallableStatement
是该规则的例外:它支持命名参数。听起来像是bug对我来说,您可能希望在元数据报告名称时不使用
@
,或者
setXXX
应使用
@
接受它(并且不使用以实现向后兼容性).GitHub问题。我什么时候可以将其合并到sql驱动程序中?@HBK-我不是Microsoft员工,所以我不能说。您可以尝试在GitHub上询问。@HBK-版本于10月19日发布。