Я хочу сделать INSERTзапись в базе данных (в моем случае это Microsoft SQL Server), используя JDBC в Java. В то же время я хочу получить идентификатор вставки. Как я могу добиться этого с помощью JDBC API?
Оставьте идентификатор, который является AutoGenrerated, в Query String sql = "INSERT INTO 'yash'.'mytable' ('name') VALUES (?)"; int primkey = 0 ; PreparedStatement pstmt = con.prepareStatement(sql, new String[] { "id" }/*Statement.RETURN_GENERATED_KEYS*/); pstmt.setString(1, name); if (pstmt.executeUpdate() > 0) { java.sql.ResultSet generatedKeys = pstmt.getGeneratedKeys (); if (generatedKeys.next()) primkey = generatedKeys.getInt(1); }
Яш
Ответы:
650
Если это автоматически сгенерированный ключ, то вы можете использовать Statement#getGeneratedKeys()для этого. Вы должны вызывать его так же, Statementкак тот, который используется для INSERT. Сначала вам нужно создать оператор с помощью Statement.RETURN_GENERATED_KEYSуведомления драйвера JDBC о возвращении ключей.
Вот основной пример:
publicvoid create(User user)throwsSQLException{try(Connection connection = dataSource.getConnection();PreparedStatement statement = connection.prepareStatement(SQL_INSERT,Statement.RETURN_GENERATED_KEYS);){
statement.setString(1, user.getName());
statement.setString(2, user.getPassword());
statement.setString(3, user.getEmail());// ...int affectedRows = statement.executeUpdate();if(affectedRows ==0){thrownewSQLException("Creating user failed, no rows affected.");}try(ResultSet generatedKeys = statement.getGeneratedKeys()){if(generatedKeys.next()){
user.setId(generatedKeys.getLong(1));}else{thrownewSQLException("Creating user failed, no ID obtained.");}}}}
Обратите внимание, что вы зависите от драйвера JDBC относительно того, работает ли он. В настоящее время большинство последних версий будут работать, но, если я прав, драйвер JDBC Oracle все еще несколько проблематичен с этим. MySQL и DB2 уже поддерживали это целую вечность. PostgreSQL начал поддерживать его не так давно. Я не могу комментировать MSSQL, так как никогда не использовал его.
Для Oracle вы можете вызвать a CallableStatementс RETURNINGпредложением или a SELECT CURRVAL(sequencename)(или любым другим специфическим для DB синтаксисом) непосредственно после INSERTтой же транзакции, чтобы получить последний сгенерированный ключ. Смотрите также этот ответ .
Лучше получить следующее значение в последовательности перед вставкой, чем получить курсор после вставки, поскольку последняя может возвращать неправильное значение в многопоточной среде (например, в любом контейнере веб-приложения). Драйвер JTDS MSSQL поддерживает getGeneratedKeys.
JeeBee
4
(следует уточнить, что я обычно использую Oracle, поэтому обычно очень низко ожидаю от возможностей драйвера JDBC).
JeeBee
7
Интересным побочным эффектом НЕ установки опции Statement.RETURN_GENERATED_KEYS является сообщение об ошибке, которое совершенно неясно: «Оператор должен быть выполнен до того, как будут получены какие-либо результаты».
Крис Винтерс
7
В generatedKeys.next()возвращается , trueесли DB возвращается сгенерированный ключ. Смотри, это ResultSet. Это close()просто, чтобы освободить ресурсы. В противном случае ваша БД исчерпает их в долгосрочной перспективе, и ваше приложение сломается Вам просто нужно написать какой-нибудь служебный метод, который выполняет задачу закрытия. Смотрите также этот и этот ответ.
BalusC
5
Правильный ответ для большинства баз данных / драйверов. Для Oracle это не работает, однако. Для Oracle измените на: connection.prepareStatement (sql, new String [] {"Имя столбца PK"});
Даррелл Тиг
24
Создать сгенерированный столбец
String generatedColumns[]={"ID"};
Передайте эту сгенерированную колонку вашему заявлению
Я использую Microsoft SQL Server 2008 R2 из однопоточного приложения на основе JDBC и извлекаю последний идентификатор без использования свойства RETURN_GENERATED_KEYS или какого-либо PreparedStatement. Выглядит примерно так:
privateint insertQueryReturnInt(StringSQLQy){ResultSet generatedKeys =null;int generatedKey =-1;try{Statement statement = conn.createStatement();
statement.execute(SQLQy);}catch(Exception e){
errorDescription ="Failed to insert SQL query: "+SQLQy+"( "+ e.toString()+")";return-1;}try{
generatedKey =Integer.parseInt(readOneValue("SELECT @@IDENTITY"));}catch(Exception e){
errorDescription ="Failed to get ID of just-inserted SQL query: "+SQLQy+"( "+ e.toString()+")";return-1;}return generatedKey;}
То, что приложение имеет только один поток, не делает невозможным условие состязания: если два клиента вставят строку и получат идентификатор с помощью вашего метода, это может привести к сбою.
11684
Почему ты? Я просто рад, что я не бедняга, которому приходится отлаживать твой код при разрешении нескольких потоков!
Мьяггард
6
При обнаружении ошибки «Неподдерживаемая функция» во время использования Statement.RETURN_GENERATED_KEYSпопробуйте следующее:
String[] returnId ={"BATCHID"};String sql ="INSERT INTO BATCH (BATCHNAME) VALUES ('aaaaaaa')";PreparedStatement statement = connection.prepareStatement(sql, returnId);int affectedRows = statement.executeUpdate();if(affectedRows ==0){thrownewSQLException("Creating user failed, no rows affected.");}try(ResultSet rs = statement.getGeneratedKeys()){if(rs.next()){System.out.println(rs.getInt(1));}
rs.close();}
Где BATCHIDавтоматически сгенерированный идентификатор.
Я использую SQLServer 2008, но у меня есть ограничение разработки: я не могу использовать новый драйвер для него, я должен использовать "com.microsoft.jdbc.sqlserver.SQLServerDriver" (я не могу использовать "com.microsoft.sqlserver.jdbc .SQLServerDriver ").
Вот почему решение conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)бросило java.lang.AbstractMethodError для меня. В этой ситуации возможное решение, которое я нашел, - это старое, предложенное Microsoft:
как получить значение @@ IDENTITY с помощью JDBC
import java.sql.*;import java.io.*;publicclassIdentitySample{publicstaticvoid main(String args[]){try{String URL ="jdbc:microsoft:sqlserver://yourServer:1433;databasename=pubs";String userName ="yourUser";String password ="yourPassword";System.out.println("Trying to connect to: "+ URL);//Register JDBC DriverClass.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();//Connect to SQL ServerConnection con =null;
con =DriverManager.getConnection(URL,userName,password);System.out.println("Successfully connected to server");//Create statement and Execute using either a stored procecure or batch statementCallableStatement callstmt =null;
callstmt = con.prepareCall("INSERT INTO myIdentTable (col2) VALUES (?);SELECT @@IDENTITY");
callstmt.setString(1,"testInputBatch");System.out.println("Batch statement successfully executed");
callstmt.execute();int iUpdCount = callstmt.getUpdateCount();boolean bMoreResults =true;ResultSet rs =null;int myIdentVal =-1;//to store the @@IDENTITY//While there are still more results or update counts//available, continue processing resultsetswhile(bMoreResults || iUpdCount!=-1){//NOTE: in order for output parameters to be available,//all resultsets must be processed
rs = callstmt.getResultSet();//if rs is not null, we know we can get the results from the SELECT @@IDENTITYif(rs !=null){
rs.next();
myIdentVal = rs.getInt(1);}//Do something with the results here (not shown)//get the next resultset, if there is one//this call also implicitly closes the previously obtained ResultSet
bMoreResults = callstmt.getMoreResults();
iUpdCount = callstmt.getUpdateCount();}System.out.println("@@IDENTITY is: "+ myIdentVal);//Close statement and connection
callstmt.close();
con.close();}catch(Exception ex){
ex.printStackTrace();}try{System.out.println("Press any key to quit...");System.in.read();}catch(Exception e){}}}
columnIndexes «Вы можете использовать функцию prepareStatement, которая принимает columnIndexes и оператор SQL.
Там, где столбцам разрешены постоянные флаги, это Statement.RETURN_GENERATED_KEYS 1 или Statement.NO_GENERATED_KEYS [2], SQL-оператор, который может содержать один или несколько символов «?» IN параметр заполнителей.
columnNames « Перечислите столбецNames как 'id', 'uniqueID', .... в целевой таблице, которая содержит автоматически сгенерированные ключи, которые должны быть возвращены. Драйвер будет игнорировать их, если оператор SQL не является INSERTоператором.
С NativeQuery в Hibernate вам нужно возвращать ResultList вместо SingleResult, потому что Hibernate изменяет собственный запрос
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id
подобно
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id LIMIT 1
если вы попытаетесь получить единственный результат, который заставит большинство баз данных (по крайней мере PostgreSQL) выдать синтаксическую ошибку. После этого вы можете получить полученный идентификатор из списка (который обычно содержит ровно один элемент).
1. createStatementМетод от Connectionне ожидайте никаких параметров. 2. executeМетод Statementожидает строку с запросом. 3. executeМетод возвращает: trueесли первым результатом является ResultSetобъект; falseесли это счетчик обновлений или нет результатов. docs.oracle.com/javase/7/docs/api/java/sql/...
String sql = "INSERT INTO 'yash'.'mytable' ('name') VALUES (?)"; int primkey = 0 ; PreparedStatement pstmt = con.prepareStatement(sql, new String[] { "id" }/*Statement.RETURN_GENERATED_KEYS*/); pstmt.setString(1, name); if (pstmt.executeUpdate() > 0) { java.sql.ResultSet generatedKeys = pstmt.
getGeneratedKeys ();if (generatedKeys.next()) primkey = generatedKeys.getInt(1); }
Ответы:
Если это автоматически сгенерированный ключ, то вы можете использовать
Statement#getGeneratedKeys()
для этого. Вы должны вызывать его так же,Statement
как тот, который используется дляINSERT
. Сначала вам нужно создать оператор с помощьюStatement.RETURN_GENERATED_KEYS
уведомления драйвера JDBC о возвращении ключей.Вот основной пример:
Обратите внимание, что вы зависите от драйвера JDBC относительно того, работает ли он. В настоящее время большинство последних версий будут работать, но, если я прав, драйвер JDBC Oracle все еще несколько проблематичен с этим. MySQL и DB2 уже поддерживали это целую вечность. PostgreSQL начал поддерживать его не так давно. Я не могу комментировать MSSQL, так как никогда не использовал его.
Для Oracle вы можете вызвать a
CallableStatement
сRETURNING
предложением или aSELECT CURRVAL(sequencename)
(или любым другим специфическим для DB синтаксисом) непосредственно послеINSERT
той же транзакции, чтобы получить последний сгенерированный ключ. Смотрите также этот ответ .источник
generatedKeys.next()
возвращается ,true
если DB возвращается сгенерированный ключ. Смотри, этоResultSet
. Этоclose()
просто, чтобы освободить ресурсы. В противном случае ваша БД исчерпает их в долгосрочной перспективе, и ваше приложение сломается Вам просто нужно написать какой-нибудь служебный метод, который выполняет задачу закрытия. Смотрите также этот и этот ответ.Создать сгенерированный столбец
Передайте эту сгенерированную колонку вашему заявлению
Используйте
ResultSet
объект для получения GeneratedKeys в оператореисточник
Я использую Microsoft SQL Server 2008 R2 из однопоточного приложения на основе JDBC и извлекаю последний идентификатор без использования свойства RETURN_GENERATED_KEYS или какого-либо PreparedStatement. Выглядит примерно так:
В этом блоге хорошо представлены три основных параметра «последнего идентификатора» SQL Server: http://msjawahar.wordpress.com/2008/01/25/how-to-find-the-last-identity-value-inserted-in-the -sql-server / - еще два не нужны.
источник
При обнаружении ошибки «Неподдерживаемая функция» во время использования
Statement.RETURN_GENERATED_KEYS
попробуйте следующее:Где
BATCHID
автоматически сгенерированный идентификатор.источник
BATCHID
Я использую SQLServer 2008, но у меня есть ограничение разработки: я не могу использовать новый драйвер для него, я должен использовать "com.microsoft.jdbc.sqlserver.SQLServerDriver" (я не могу использовать "com.microsoft.sqlserver.jdbc .SQLServerDriver ").
Вот почему решение
conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)
бросило java.lang.AbstractMethodError для меня. В этой ситуации возможное решение, которое я нашел, - это старое, предложенное Microsoft: как получить значение @@ IDENTITY с помощью JDBCЭто решение сработало для меня!
Надеюсь, это поможет!
источник
Вместо комментария я просто хочу ответить на пост.
Интерфейс java.sql.PreparedStatement
columnIndexes «Вы можете использовать функцию prepareStatement, которая принимает columnIndexes и оператор SQL. Там, где столбцам разрешены постоянные флаги, это Statement.RETURN_GENERATED_KEYS 1 или Statement.NO_GENERATED_KEYS [2], SQL-оператор, который может содержать один или несколько символов «?» IN параметр заполнителей.
Синтакс «
Пример:
columnNames « Перечислите столбецNames как
'id', 'uniqueID', ...
. в целевой таблице, которая содержит автоматически сгенерированные ключи, которые должны быть возвращены. Драйвер будет игнорировать их, если оператор SQL не являетсяINSERT
оператором.Синтакс «
Пример:
Полный пример:
источник
Вы можете использовать следующий код Java, чтобы получить новый вставленный идентификатор.
источник
С NativeQuery в Hibernate вам нужно возвращать ResultList вместо SingleResult, потому что Hibernate изменяет собственный запрос
подобно
если вы попытаетесь получить единственный результат, который заставит большинство баз данных (по крайней мере PostgreSQL) выдать синтаксическую ошибку. После этого вы можете получить полученный идентификатор из списка (который обычно содержит ровно один элемент).
источник
Можно использовать и с обычными
Statement
(не толькоPreparedStatement
)источник
В моем случае ->
источник
Если вы используете Spring JDBC, вы можете использовать класс Spring GeneratedKeyHolder для получения вставленного идентификатора.
Посмотрите этот ответ ... Как получить вставленный идентификатор с помощью Spring Jdbctemplate.update (String sql, obj ... args)
источник
источник
createStatement
Метод отConnection
не ожидайте никаких параметров. 2.execute
МетодStatement
ожидает строку с запросом. 3.execute
Метод возвращает:true
если первым результатом являетсяResultSet
объект;false
если это счетчик обновлений или нет результатов. docs.oracle.com/javase/7/docs/api/java/sql/...