Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/389.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java HSQLDB在准备callablestatement时为过程设置了错误的输入参数名称_Java_Stored Procedures_Jdbc_Hsqldb - Fatal编程技术网

Java HSQLDB在准备callablestatement时为过程设置了错误的输入参数名称

Java HSQLDB在准备callablestatement时为过程设置了错误的输入参数名称,java,stored-procedures,jdbc,hsqldb,Java,Stored Procedures,Jdbc,Hsqldb,这件事快把我逼疯了 我在一个junit测试中使用HSQLDB作为内存数据库,测试的是我为调用存储过程而编写的一组通用类 初始化数据库: 然后在准备语句的类中的某个点,我使用setObject方法注册输入参数: ... CallableStatement callableStatement = con.prepareCall("{call sp_say_hi(?)}"); callableStatement.setObject("greeting_p", "Hola"); ... setObje

这件事快把我逼疯了

我在一个junit测试中使用HSQLDB作为内存数据库,测试的是我为调用存储过程而编写的一组通用类

初始化数据库:

然后在准备语句的类中的某个点,我使用setObject方法注册输入参数:

...
CallableStatement callableStatement = con.prepareCall("{call sp_say_hi(?)}");
callableStatement.setObject("greeting_p", "Hola");
...
setObject方法引发JavaSqlException,原因如下:

Caused by: org.hsqldb.HsqlException: Column not found: greeting_p
at org.hsqldb.error.Error.error(Unknown Source)
at org.hsqldb.error.Error.error(Unknown Source)
通过使用调试器,我发现org.hsqldb.jdbc.JDBCCallableStatement类中有一个包私有方法,它是hsqldb对CallableStatement的实现,方法名为findParameterIndex,在setObject方法中调用,检查提供的参数是否存在于程序的参数映射中:

int findParameterIndex(String parameterName) throws SQLException {

    if (isClosed || connection.isClosed) {
        checkClosed();
    }

    int index = parameterNameMap.get(parameterName, -1);

    if (index >= 0) {
        return index + 1;
    }

    throw JDBCUtil.sqlException(ErrorCode.JDBC_COLUMN_NOT_FOUND,
                            parameterName);
}
通过使用调试器查看该映射,我能够看到hsqldb错误地设置了参数名,至少在该映射中是这样的:

[@p1, null, null, null, null, null, null, null]
我可以通过更改setObject方法调用中的名称进行验证:

    callableStatement.setObject("@p1", "Hola");
在那之后,它工作得很好

奇怪的是,如果我使用DatabaseMetaData.getprocedureclumns方法检索该过程的元数据,那么从jdbc元数据的角度来看,参数的名称是正确的:

DatabaseMetaData dbMetadata = con.getMetaData();
    ResultSet rs = dbMetadata.getProcedureColumns(con.getCatalog(),
            con.getSchema(),
            "SP_SAY_HI",
            "%_P");
        while(rs.next()) {
          // get stored procedure metadata
          String procedureCatalog     = rs.getString(1);
          String procedureSchema      = rs.getString(2);
          String procedureName        = rs.getString(3);
          String columnName           = rs.getString(4);
          short  columnReturn         = rs.getShort(5);
          int    columnDataType       = rs.getInt(6);
          String columnReturnTypeName = rs.getString(7);
          int    columnPrecision      = rs.getInt(8);
          int    columnByteLength     = rs.getInt(9);
          short  columnScale          = rs.getShort(10);
          short  columnRadix          = rs.getShort(11);
          short  columnNullable       = rs.getShort(12);
          String columnRemarks        = rs.getString(13);

          System.out.println("stored Procedure name="+procedureName);
          System.out.println("procedureCatalog=" + procedureCatalog);
          System.out.println("procedureSchema=" + procedureSchema);
          System.out.println("procedureName=" + procedureName);
          System.out.println("columnName=" + columnName);
          System.out.println("columnReturn=" + columnReturn);
          System.out.println("columnDataType=" + columnDataType);
          System.out.println("columnReturnTypeName=" + columnReturnTypeName);
          System.out.println("columnPrecision=" + columnPrecision);
          System.out.println("columnByteLength=" + columnByteLength);
          System.out.println("columnScale=" + columnScale);
          System.out.println("columnRadix=" + columnRadix);
          System.out.println("columnNullable=" + columnNullable);
          System.out.println("columnRemarks=" + columnRemarks);
        }
它打印出:

stored Procedure name=SP_SAY_HI
procedureCatalog=PUBLIC
procedureSchema=PUBLIC
procedureName=SP_SAY_HI
columnName=GREETING_P
columnReturn=1
columnDataType=12
columnReturnTypeName=CHARACTER VARYING
columnPrecision=10
columnByteLength=0
columnScale=0
columnRadix=0
columnNullable=1
columnRemarks=null
注意,名称是大写的,我已经检查过了。我在setObject方法中将参数名的注册改为大写,以查看这是否有帮助,但没有任何区别

更新:
我在HSQLDB issue tracking system中创建了一个票证,他们刚刚修复了它并将其提交到当前realease:

我认为在将变量绑定到存储过程调用时,使用继承自的setX方法(例如:

从以下的JavaDocs:

当方法prepareCall完成时,一些驱动程序可能会将调用语句发送到数据库;其他人可能会等待执行CallableStatement对象


如果驱动程序在调用execute之前没有与DB通信,那么它也无法知道参数的名称,因为JDBC查询中的绑定变量总是匿名的。当绑定发生时,HSQLDB驱动程序似乎确实不知道实际的参数名,因为它在内部使用占位符名@p1等

我在HSQLDB问题跟踪系统中创建了一个记录单,他们刚刚修复了它并提交到下一个版本,了解更多信息:

您所说的很有意义,因为它解释了为什么一些框架,如Spring JdbcTemplate,特别是SimpleJDBCall及其助手类在设置参数时使用基于位置的方法,从他们的代码中我看到,他们所做的是首先使用db元数据检索参数的位置,例如使用GetProcedureClumns方法,然后在setX方法中使用该位置。然而,有趣的是,如果驱动程序在该阶段没有与db通信,那么它如何知道'@p1'参数的存在。如何在变量sqlCall中,用于过程调用的SQL看起来像吗?如果它有绑定占位符问号,那么驱动程序知道需要多少参数。@raspacorp-我同意Mick的评估。我不认为这是您或HSQLDB做得不正确的问题,可能只是HSQLDB在.set中赋值时不支持使用参数名。。。声明。HSQLDB没有提到可选参数,因此如果所有参数都必须在调用中表示,那么它们的值可以简单地由数字1..n按照过程声明定义的顺序提供。@MickMnemonic抱歉,我没有在问题中提供sqlCall的值,我只是更新了它:{CALL sp_say_hi}谢谢你的最新更新。请考虑在这个问题上添加你自己的答案,表明这个问题将被固定在下一版本的HQLDB中。
stored Procedure name=SP_SAY_HI
procedureCatalog=PUBLIC
procedureSchema=PUBLIC
procedureName=SP_SAY_HI
columnName=GREETING_P
columnReturn=1
columnDataType=12
columnReturnTypeName=CHARACTER VARYING
columnPrecision=10
columnByteLength=0
columnScale=0
columnRadix=0
columnNullable=1
columnRemarks=null
callableStatement.setString(1, "Hola");