Вернуть параметр ROWID из оператора вставки, используя соединение JDBC с оракулом

Кажется, я не могу получить правильную волшебную комбинацию, чтобы сделать эту работу:


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; конец; block, то я отлично получаю параметр, используя обычный вызов registerOutParameter(). Я действительно предпочел бы не обертывать все мои операторы вставки в PL/SQL - так чего же не хватает выше?


person Goyuix    schedule 25.03.2009    source источник


Ответы (5)


Несколько вещей, которые вам нужно сделать

  • Изменить CallableStatement на OracleCallableStatement
  • Попробуйте вернуться к ЧИСЛУ, например: 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:

person Achille    schedule 04.05.2009

Обычно вы не хотите, чтобы база данных кода зависела. Вместо OraclePreparedStatement следует использовать CallableStatement.

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);
}
person Community    schedule 19.05.2009
comment
Этот синтаксический сахар был именно тем, что мне было нужно - {звонить} - person John Strickler; 21.04.2011
comment
Работал и для меня. Следует помнить, что если у вас есть параметр IN и параметр OUT, индексы всегда растут. Итак, если вы делаете { call INSERT INTO tbl (x, y) VALUES (seq.NEXTVAL, ?) RETURNING x INTO ? }, то seq.NEXTVAL возвращается в statement.getLong(2), а не getLong(1). - person 0xbe5077ed; 21.01.2016

Не знаю, применимо это или нет, поскольку вы не указываете, какую версию вы используете.

От Оракл Металинк:

Причина

В драйвере JDBC версии 10.1.0.x возврат DML не поддерживается:

Согласно JDBC FAQ: «10.1.0 (10g r1) Поддерживается ли возврат DML? Нет в текущих драйверах. Однако у нас есть планы поддерживать его в драйверах после 10.1.0. На этот раз мы действительно серьезно».

Поскольку код приложения пытается использовать неподдерживаемые функции JDBC, возникают ошибки.

Решение

Обновите драйвер JDBC до версии 10.2.0.x, поскольку, согласно часто задаваемым вопросам, драйверы JDBC версии 10.2.0.x поддерживают предложение возврата:

«10.2.0 (10g r2) Поддерживается ли возвращение DML? ДА! И самое время. Подробности см. в Руководстве разработчика».

EDIT Просто для улыбки, вы можете проверить версию JDBC, которую Oracle считает используемой:

 // 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 или новее, то у меня нет идей, и, возможно, нужно обратиться в службу поддержки оракула...

person DCookie    schedule 25.03.2009
comment
Спасибо за информацию, вот различные версии, которые я использую: Версия Java: 1.6.0_12-b04 Версия виртуальной машины: 11.2-b01 (сервер HotSpot) Сервер Oracle: 10.2.0.4 Клиент Oracle: от 11.1.0.7.0 до ojdbc6. банка - person Goyuix; 25.03.2009

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', '[email protected]', '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/

person SüniÚr    schedule 02.09.2014
comment
Этот ответ требует гораздо больше голосов за использование prepareStatement(sql, columnNames), который работает "из коробки". - person Matthieu; 07.07.2021

Попробуйте использовать ? вместо :rowid0 в строке SQL. Раньше у меня были проблемы с именованными параметрами и Oracle.

person Pablo Santa Cruz    schedule 25.03.2009