【问题标题】:Return ROWID Parameter from insert statement using JDBC connection to oracle使用 JDBC 连接到 oracle 从插入语句返回 ROWID 参数
【发布时间】:2009-03-25 17:09:34
【问题描述】:

我似乎无法找到正确的魔法组合来完成这项工作:


OracleDataSource ods = new oracle.jdbc.pool.OracleDataSource();
ods.setURL("jdbc:oracle:thin:app_user/pass@server:1521:sid");
DefaultContext conn = ods.getConnection();
CallableStatement st = conn.prepareCall("INSERT INTO tableA (some_id) VALUES (1) RETURNING ROWID INTO :rowid0");
st.registerReturnParameter(1, OracleTypes.ROWID);
st.execute();

我得到的错误是“违反协议”。如果我更改为 registerOutParameter(),我会收到通知说我尚未注册所有返回变量。如果我将语句包装在 PL/SQL 开头;结尾;块然后我使用常规的 registerOutParameter() 调用得到参数就好了。我真的希望避免将所有插入语句包装在 PL/SQL 中 - 那么上面缺少什么?

【问题讨论】:

    标签: java oracle jdbc


    【解决方案1】:

    通常你不想让代码依赖于数据库。您应该使用 CallableStatement,而不是 OraclePreparedStatement。

    CallableStatement statement = connection.prepareCall("{call INSERT INTO tableA (some_id) VALUES (1) RETURNING ROWID INTO ? }");
    statement.registerOutParameter( 1, Types.VARCHAR );
    
    int updateCount = statement.executeUpdate();
    if (updateCount > 0) {
       return statement.getString(1);
    }
    

    【讨论】:

    • 这个语法糖正是我所需要的——{call }
    • 也为我工作。要注意的是,如果您有一个 IN 参数和一个 OUT 参数,索引总是会上升。因此,如果您执行{ call INSERT INTO tbl (x, y) VALUES (seq.NEXTVAL, ?) RETURNING x INTO ? },那么seq.NEXTVAL 将在statement.getLong(2) 中返回,而不是getLong(1)
    【解决方案2】:

    你需要做的一些事情

    • 将 CallableStatement 更改为 OracleCallableStatement
    • 尝试返回一个NUMBER,即:OracleTypes.Number

    从查询返回信息的示例代码:

    OraclePreparedStatement pstmt = (OraclePreparedStatement)conn.prepareStatement(
           "delete from tab1 where age < ? returning name into ?");
    pstmt.setInt(1,18);
    
    /** register returned parameter
      * in this case the maximum size of name is 100 chars
      */
    pstmt.registerReturnParameter(2, OracleTypes.VARCHAR, 100);
    
    // process the DML returning statement
    count = pstmt.executeUpdate();
    if (count>0)
    {
      ResultSet rset = pstmt.getReturnResultSet(); //rest is not null and not empty
      while(rset.next())
      {
        String name = rset.getString(1);
        ...
      }
    }
    

    有关 Oracle 的 JDBC 扩展的更多信息:

    【解决方案3】:

    不知道这是否适用,因为您没有指定您使用的版本。

    来自 Oracle Metalink:

    原因

    在 10.1.0.x JDBC 驱动中,不支持返回 DML:

    根据 JDBC 常见问题解答: "10.1.0 (10g r1) 是否支持 DML 返回? 不在当前的驱动程序中。但是,我们确实计划在 10.1.0 后的驱动程序中支持它。我们 这次是认真的。”

    当应用程序代码尝试使用不受支持的 JDBC 功能时,会引发错误。

    解决方案

    将 JDBC 驱动程序升级到 10.2.0.x,因为根据常见问题解答,10.2.0.x JDBC 驱动程序确实支持返回子句:

    "10.2.0 (10g r2) 是否支持 DML 返回? 是的!现在是时候了。有关详细信息,请参阅开发人员指南。 "

    编辑 只是为了笑,您可以检查 Oracle 认为它正在使用的 JDBC 版本:

     // Create Oracle DatabaseMetaData object
      DatabaseMetaData meta = conn.getMetaData();
    
      // gets driver info:
      System.out.println("JDBC driver version is " + meta.getDriverVersion());
    

    如果这显示 JDBC 驱动程序 10.2.0.x 或更高版本,那么我没有想法,也许对 oracle 的支持请求是按顺序...

    【讨论】:

    • 感谢您的信息,这是我正在使用的各种版本: Java 版本:1.6.0_12-b04 虚拟机版本:11.2-b01(HotSpot 服务器) Oracle 服务器:10.2.0.4 Oracle 客户端: 11.1.0.7.0 到 ojdbc6.jar
    【解决方案4】:
    PreparedStatement prepareStatement = connection.prepareStatement("insert...",
                new String[] { "your_primary_key_column_name" });
    
        prepareStatement.executeUpdate();
    
        ResultSet generatedKeys = prepareStatement.getGeneratedKeys();
        if (null != generatedKeys && generatedKeys.next()) {
             Long primaryKey = generatedKeys.getLong(1);
        }
    

    我已经找到了非常有效的答案。我可以从 JAVA 插入,并用密钥返回。

    完整版:

    CREATE TABLE STUDENTS
    (
       STUDENT_ID   NUMBER NOT NULL PRIMARY KEY,
       NAME         VARCHAR2 (50 BYTE),
       EMAIL        VARCHAR2 (50 BYTE),
       BIRTH_DATE   DATE
    );
    
    
    CREATE SEQUENCE STUDENT_SEQ
       START WITH 0
       MAXVALUE 9999999999999999999999999999
       MINVALUE 0;
    

    还有 Java 代码

    String QUERY = "INSERT INTO students "+
                   "  VALUES (student_seq.NEXTVAL,"+
                   "         'Harry', 'harry@hogwarts.edu', '31-July-1980')";
    
    // load oracle driver
    Class.forName("oracle.jdbc.driver.OracleDriver");
    
    // get database connection from connection string
    Connection connection = DriverManager.getConnection(
            "jdbc:oracle:thin:@localhost:1521:sample", "scott", "tiger");
    
    // prepare statement to execute insert query
    // note the 2nd argument passed to prepareStatement() method
    // pass name of primary key column, in this case student_id is
    // generated from sequence
    PreparedStatement ps = connection.prepareStatement(QUERY,
            new String[] { "student_id" });
    
    // local variable to hold auto generated student id
    Long studentId = null;
    
    // execute the insert statement, if success get the primary key value
    if (ps.executeUpdate() > 0) {
    
        // getGeneratedKeys() returns result set of keys that were auto
        // generated
        // in our case student_id column
        ResultSet generatedKeys = ps.getGeneratedKeys();
    
        // if resultset has data, get the primary key value
        // of last inserted record
        if (null != generatedKeys && generatedKeys.next()) {
    
            // voila! we got student id which was generated from sequence
            studentId = generatedKeys.getLong(1);
        }
    
    }
    

    来源:http://viralpatel.net/blogs/oracle-java-jdbc-get-primary-key-insert-sql/

    【讨论】:

    【解决方案5】:

    尝试在您的 SQL 字符串上使用 ? 而不是 :rowid0。我之前在命名参数和 Oracle 方面遇到过问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-22
      相关资源
      最近更新 更多