【问题标题】:Sybase IN and OUT parametersSybase IN 和 OUT 参数
【发布时间】:2011-04-29 20:32:13
【问题描述】:

我对 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

【问题讨论】:

    标签: stored-procedures jdbc sqlanywhere out-parameters jconnect


    【解决方案1】:

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

    我怀疑有问题的驱动程序希望参数按顺序传递/注册(即 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));
    

    【讨论】:

    • 是的。程序相同,只是调用方式不同。我还怀疑这个驱动程序会重新排序参数。但由于我无法想象主要 RDBMS 的驱动程序中存在如此可怕的缺陷,我想也许我有什么问题......
    • 我想反编译驱动,但用google找不到,只有新版本。你有指向这个有问题的驱动程序的链接吗?
    • 你可以在这里找到它:sybase.com/detail?id=1041013。 jconn3.jar 包含在 jconnect 6 包中
    • 我猜你的赏金速度不够快......对不起。我不知道这个赏金业务。我现在也在 meta 上提出了这个问题:meta.stackexchange.com/questions/84785/…
    • 不在乎赏金 :-D 手头的问题是令人兴奋的!
    【解决方案2】:

    我在 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
    

    【讨论】:

    • 您在问题中提到的第二个变体导致 null,我的 Oracle 9.2 JDBC 驱动程序为 null。
    • 您在问题中写道:“这是 JDBC 驱动程序中的一个非常严重的错误,还是我完全遗漏了什么?”这就是为什么我尝试使用 Oracle 来确保这仅在您的 JDBC 驱动程序中。基于此,我可以写:是的 Lukas,这可能是您的 sybase jdbc 驱动程序中的一个错误,与 Oracle 配合得很好。无论如何:感谢您投票否决唯一花时间调查此问题的人.. :-(
    • 啊,看。你自动获得了一半的赏金...... ;-)
    • 谢谢 :-) 有趣的是,这些毫无价值的声誉点如何激励无聊的人
    【解决方案3】:
    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-20
      • 1970-01-01
      • 2011-10-12
      • 2014-08-13
      • 2016-07-30
      • 1970-01-01
      • 2015-12-14
      • 2021-11-19
      相关资源
      最近更新 更多