5

我对 Sybase JDBC 驱动程序如何处理带有混合参数INOUT参数的存储过程感到疯狂。看看这个简单的存储过程:

CREATE OR REPLACE PROCEDURE p (IN i1 INT, OUT o1 INT, IN i2 INT, OUT o2 INT)
BEGIN
    set o1 = i1;
    set o2 = i2;
END

这就是我用 JDBC 来称呼它的方式:

CallableStatement c = connection.prepareCall("{ call dba.p(?, ?, ?, ?) }");
c.setInt(1, 1);
c.setInt(3, 2);
c.registerOutParameter(2, Types.INTEGER);
c.registerOutParameter(4, Types.INTEGER);
c.execute();
System.out.println(c.getObject(2));
System.out.println(c.getObject(4));

但这导致

1
null

这是怎么回事??这是 JDBC 驱动程序中的一个非常邪恶的错误,还是我完全遗漏了什么?通过反复试验,我发现这是一种工作方式:

c.setInt(1, 1);
c.setInt(2, 2);
c.registerOutParameter(3, Types.INTEGER);
c.registerOutParameter(4, Types.INTEGER);
c.execute();
System.out.println(c.getObject(3));
System.out.println(c.getObject(4));

现在结果是

1
2

JDBC驱动是不是偷偷重新排序INOUT参数??

我正在使用 SQL Anywhere 12 和 jconn3.jar

4

3 回答 3

7

看起来像驱动程序中的错误。

我怀疑有问题的驱动程序希望参数按顺序传递/注册(即 1、2、3、4)。当您执行 registerOut(2) 时,该语句显然忘记了您执行 set(3) :-)

或者,可能是,所有的 OUT 都应该在所有的 IN 之后完成。再说一次,这是驱动程序中的错误。

更新

等等,你没有改变第二个变种的程序吗?这个结果没有任何意义。除非,如您所说,驱动程序确实重新排序。这是不寻常的,至少可以这么说。

更新 2

我已经反编译了驱动程序。它围绕参数做了一些非常有趣的游戏,并且在所有这些慢跑中,我觉得它们很有可能在那里出现错误,但到目前为止我还没有清楚地看到它。

我注意到的唯一有趣的事情是,显然如果位置 n 的参数没有输出,驱动程序将向前扫描参数,直到找到该值;如果未找到值,则转到下一行:

  s.registerOutParameter(5,Types.INT);
  ...
  // no out value at position 4, it will go to 5 and get the value
  rs.getInteger(4);

更新 3

查看示例 1 中所有 4 个参数的输出可能会很有趣,即:

CallableStatement c = connection.prepareCall("{ call dba.p(?, ?, ?, ?) }");
c.setInt(1, 1);
c.setInt(3, 2);
c.registerOutParameter(2, Types.INTEGER);
c.registerOutParameter(4, Types.INTEGER);
c.execute();
System.out.println(c.getObject(1));
System.out.println(c.getObject(2));
System.out.println(c.getObject(3));
System.out.println(c.getObject(4));
于 2011-05-10T04:37:37.697 回答
4

我在 Oracle 9.2 上试过这个,它按预期工作。我认为这个问题与您的 JDBC 驱动程序有关,而不是与 JDBC 本身有关。

    public static void main(String[] args) throws Exception {

    Connection connection = getConnection();

    CallableStatement c = connection.prepareCall("{ call p(?, ?, ?, ?) }");
    c.setInt(1, 1);
    c.setInt(3, 2);
    c.registerOutParameter(2, Types.INTEGER);
    c.registerOutParameter(4, Types.INTEGER);
    c.execute();
    System.out.println(c.getObject(2));
    System.out.println(c.getObject(4));

}

输出:

Connected to database
1
2
于 2011-05-09T11:25:24.097 回答
1
Below sybase stored procedure works for me
public String IDGEN(String tableName,  Connection con , LOG _log)
    { 
        String strReturnValue = "-1"; 
        try
        {
             CallableStatement cs = con.prepareCall("{call usp_NEWPK_string_v6(?,?)}");
             cs.registerOutParameter(2,java.sql.Types.NUMERIC);
             cs.setString(1,tableName);
             cs.setInt(2,0);
             cs.execute();
             strReturnValue = cs.getLong(2) + "";

        } catch (Exception ex) {
            _log.logInstance(" ERROR: [IDGEN] " + ex.getMessage()); 
        }
        return strReturnValue;
    } 
// abobjects.com

create proc usp_NEWPK_string_v6 (@tablename  varchar(32) , @ID  numeric output
          )
as
declare @newValue     numeric
declare @oldValue  numeric
select @oldValue=IDGEN_ID from DB_IDGEN where IDGEN_TableName = @tablename
select @newValue=@oldValue + 1 from DB
 _IDGEN where IDGEN_TableName = @tablename
update DB_IDGEN set IDGEN_ID = @newValue where IDGEN_TableName = @tablename
select @ID  = @oldValue
return
于 2014-01-13T18:35:08.087 回答