Этот вопрос уже имеет ответ здесь:
Там некоторый путь состоит в том, чтобы получить значение от последней вставленной строки?
Я вставляю строку, где PK автоматически увеличится должный упорядочить созданный, и я хотел бы получить этот порядковый номер. Только PK, как гарантируют, будет уникален в таблице.
Я использую Java с JDBC и Oracle.
Я забыл добавлять, что я хотел бы получить это значение с помощью набора результатов ниже. (Я попробовал это mysql, и он работал успешно, но я должен был переключиться на Oracle, и теперь я получаю строковое представление идентификатора а не на самом деле порядкового номера),
Statement stmt = conn.createStatement();
stmt.executeUpdate(insertCmd, Statement.RETURN_GENERATED_KEYS);
stmt.RETURN_GENERATED_KEYS;
ResultSet rs = stmt.getGeneratedKeys();
if(rs.next()){
log.info("Successful insert");
id = rs.getString(1);
}
Вышеупомянутый отрывок возвратил бы значение интервала столбца, сохраненное в mysql таблице. Но так как я переключился на Oracle, возвращенное значение является теперь странным строковым значением.
Вы пытаетесь воспользоваться пунктом RETURNING
. Настроим таблицу примеров и последовательность:
CREATE TABLE "TEST"
( "ID" NUMBER NOT NULL ENABLE,
"NAME" VARCHAR2(100 CHAR) NOT NULL ENABLE,
CONSTRAINT "PK_TEST" PRIMARY KEY ("ID")
);
CREATE SEQUENCE SEQ_TEST;
Теперь ваш Java код должен выглядеть так:
String insertSql = "BEGIN INSERT INTO TEST (ID, NAME) VALUES (SEQ_TEST.NEXTVAL(), ?) RETURNING ID INTO ?; END;";
java.sql.CallableStatement stmt = conn.prepareCall(insertSql);
stmt.setString(1, "John Smith");
stmt.registerOutParameter(2, java.sql.Types.VARCHAR);
stmt.execute();
int id = stmt.getInt(2);
Это не согласуется с другими базами данных, но при использовании Oracle, getGeneratedKeys()
возвращает ROWID для вставленной строки при использовании Statement.RETURN_GENERATEDKEYS
. Поэтому вам необходимо использовать oracle.sql.ROWID
проприетарный тип, чтобы "прочитать" его:
Statement stmt = connection.createStatement();
stmt.executeUpdate(insertCmd, Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stmt.getGeneratedKeys();
oracle.sql.ROWID rid = (oracle.sql.ROWID) rs.getObject(1);
Но это не даст вам сгенерированный ID PK. При работе с Oracle, вы должны использовать метод executeUpdate(String sql, int[] columnIndexes)
или executeUpdate(String sql, String[] columnNames)
вместо executeUpdate(String sql, int autoGeneratedKeys)
, чтобы получить сгенерированное значение последовательности. Что-то вроде этого (адаптируйте значение к индексу или имени столбца вашего первичного ключа):
stmt.executeUpdate(INSERT_SQL, new int[] {1});
ResultSet rs = stmt.getGeneratedKeys();
Или
stmt.executeUpdate(INSERT_SQL, new String[] {"ID"});
ResultSet rs = stmt.getGeneratedKeys();
Пока вы копаете немного больше об этом, кажется, что этот подход показан в документации Spring (как упоминалось здесь), так что, ну, я думаю, что это не может быть полностью неправильным. Но, к сожалению, на самом деле она не портативна и может не работать на других платформах.
. Вместо этого следует использовать ResultSet#getLong()
. Напрасно попробуйте ResultSet#getRowId()
и в конце концов произнесите его на oracle.sql.ROWID
. Если возвращаемая шестнадцатеричная строка на самом деле является идентификатором в шестнадцатеричном представлении, то можно попробовать преобразовать её в десятичную с помощью Long#valueOf()
или Integer#valueOf()
.
Long id = Long.valueOf(hexId, 16);
Тем не менее, JDBC драйвер Oracle долгое время не поддерживал ResultSet#getGeneratedKeys()
и до сих пор вызывает некоторые затруднения. Если вы не можете получить это право, то вы должны выполнить SELECT CURRVAL (имя последовательности)
на том же заявлении, как вы сделали вставить
, или новое заявление внутри той же операции, если это было PreparedStatement
. Основной пример:
public void create(User user) throws SQLException {
Connection connection = null;
PreparedStatement preparedStatement = null;
Statement statement = null;
ResultSet generatedKeys = null;
try {
connection = daoFactory.getConnection();
preparedStatement = connection.prepareStatement(SQL_INSERT);
preparedStatement.setValue(1, user.getName());
// Set more values here.
int affectedRows = preparedStatement.executeUpdate();
if (affectedRows == 0) {
throw new SQLException("Creating user failed, no rows affected.");
}
statement = connection.createStatement();
generatedKeys = statement.executeQuery(SQL_CURRVAL);
if (generatedKeys.next()) {
user.setId(generatedKeys.getLong(1));
} else {
throw new SQLException("Creating user failed, no generated key obtained.");
}
} finally {
close(generatedKeys);
close(statement);
close(preparedStatement);
close(connection);
}
}
О, из вашего примера кода следующая строка
stmt.RETURN_GENERATED_KEYS;
совершенно лишняя. Удалите ее.
Вы можете найти здесь еще один пример, который я написал ранее о получении сгенерированных ключей, он использует обычный подход getGeneratedKeys()
.