Я хочу INSERT
запись в базе данных (которая является Microsoft SQL Server в моем случае) с использованием JDBC в Java. В то же время я хочу получить идентификатор вставки. Как я могу достичь этого с помощью API JDBC?
Как получить идентификатор вставки в JDBC?
Ответ 1
Если это автоматически сгенерированный ключ, для этого вы можете использовать Statement#getGeneratedKeys()
. Вам нужно вызвать его в том же Statement
что и в том, что используется для INSERT
. Сначала вам нужно создать оператор using Statement.RETURN_GENERATED_KEYS
чтобы уведомить драйвер JDBC о возврате ключей.
Вот базовый пример:
public void create(User user) throws SQLException {
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) {
throw new SQLException("Creating user failed, no rows affected.");
}
try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
if (generatedKeys.next()) {
user.setId(generatedKeys.getLong(1));
}
else {
throw new SQLException("Creating user failed, no ID obtained.");
}
}
}
}
Обратите внимание, что вы зависите от драйвера JDBC относительно того, работает ли он. В настоящее время большинство из последних версий будут работать, но если я прав, драйвер Oracle JDBC по-прежнему несколько хлопот с этим. MySQL и DB2 уже давно поддерживали его. PostgreSQL начал поддерживать его совсем недавно. Я не могу комментировать MSSQL, поскольку я никогда не использовал его.
Для Oracle вы можете вызывать CallableStatement
с предложением RETURNING
или SELECT CURRVAL(sequencename)
(или любым SELECT CURRVAL(sequencename)
синтаксисом, специфичным для БД), непосредственно после INSERT
в той же транзакции, чтобы получить последний сгенерированный ключ. См. Также этот ответ.
Ответ 2
-
Создать созданный столбец
String generatedColumns[] = { "ID" };
-
Передайте этот генный столбец в ваше утверждение
PreparedStatement stmtInsert = conn.prepareStatement(insertSQL, generatedColumns);
-
Используйте объект
ResultSet
для извлечения выражения GeneratedKeys on StatementResultSet rs = stmtInsert.getGeneratedKeys(); if (rs.next()) { long id = rs.getLong(1); System.out.println("Inserted ID -" + id); // display inserted record }
Ответ 3
Я ударяю Microsoft SQL Server 2008 R2 из однопоточного приложения на основе JDBC и вытягиваю последний идентификатор без использования свойства RETURN_GENERATED_KEYS или любого PreparedStatement. Выглядит примерно так:
private int insertQueryReturnInt(String SQLQy) {
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;
}
Это сообщение в блоге прекрасно изолирует три основных варианта "последнего идентификатора" SQL Server: http://msjawahar.wordpress.com/2008/01/25/how-to-find-the-last-identity-value-inserted-in-the-sql-server/ - еще не нужны другие два.
Ответ 4
При обнаружении ошибки "Неподдерживаемая функция" во время использования 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) {
throw new SQLException("Creating user failed, no rows affected.");
}
try (ResultSet rs = statement.getGeneratedKeys()) {
if (rs.next()) {
System.out.println(rs.getInt(1));
}
rs.close();
}
Где BATCHID
- автоматически сгенерированный идентификатор.
Ответ 5
Я использую SQLServer 2008, но у меня есть ограничение на разработку: я не могу использовать для него новый драйвер, я должен использовать "com.microsoft.jdbc.sqlserver.SQLServerDriver" (I не может использовать "com.microsoft.sqlserver.jdbc.SQLServerDriver" ).
Вот почему решение conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)
выбрало для меня java.lang.AbstractMethodError.
В этой ситуации возможное решение, которое я нашел, является старым, предложенным Microsoft:
Как получить значение @@IDENTITY с помощью JDBC
import java.sql.*;
import java.io.*;
public class IdentitySample
{
public static void 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 Driver
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
//Connect to SQL Server
Connection 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 statement
CallableStatement 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 resultsets
while (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 @@IDENTITY
if (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)
{
}
}
}
Это решение сработало для меня!
Надеюсь, это поможет!
Ответ 6
Вместо комментария я просто хочу ответить на пост.
Интерфейс java.sql.PreparedStatement
-
columnIndexes "Вы можете использовать функцию prepareStatement, которая принимает аргументы columnIndexes и SQL. Где columnIndexes допускают постоянные флаги: Statement.RETURN_GENERATED_KEYS 1 или Statement.NO_GENERATED_KEYS [2], оператор SQL, который может содержать один или несколько '?' Заполнители параметров IN.
СИНТАКСИС "
Connection.prepareStatement(String sql, int autoGeneratedKeys) Connection.prepareStatement(String sql, int[] columnIndexes)
Пример:
PreparedStatement pstmt = conn.prepareStatement( insertSQL, Statement.RETURN_GENERATED_KEYS );
-
columnNames "Перечислить
'id', 'uniqueID',...
типа'id', 'uniqueID',...
в целевой таблице, содержащей автоматически сгенерированные ключи, которые должны быть возвращены. Драйвер игнорирует их, если оператор SQL не является операторомINSERT
.СИНТАКСИС "
Connection.prepareStatement(String sql, String[] columnNames)
Пример:
String columnNames[] = new String[] { "id" }; PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
Полный пример:
public static void insertAutoIncrement_SQL(String UserName, String Language, String Message) {
String DB_URL = "jdbc:mysql://localhost:3306/test", DB_User = "root", DB_Password = "";
String insertSQL = "INSERT INTO 'unicodeinfo'( 'UserName', 'Language', 'Message') VALUES (?,?,?)";
//"INSERT INTO 'unicodeinfo'('id', 'UserName', 'Language', 'Message') VALUES (?,?,?,?)";
int primkey = 0 ;
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn = DriverManager.getConnection(DB_URL, DB_User, DB_Password);
String columnNames[] = new String[] { "id" };
PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
pstmt.setString(1, UserName );
pstmt.setString(2, Language );
pstmt.setString(3, Message );
if (pstmt.executeUpdate() > 0) {
// Retrieves any auto-generated keys created as a result of executing this Statement object
java.sql.ResultSet generatedKeys = pstmt.getGeneratedKeys();
if ( generatedKeys.next() ) {
primkey = generatedKeys.getInt(1);
}
}
System.out.println("Record updated with id = "+primkey);
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
Ответ 7
С Hibernate NativeQuery вам нужно вернуть 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) бросать синтаксическую ошибку. Впоследствии вы можете получить полученный идентификатор из списка (который обычно содержит ровно один элемент).
Ответ 8
Его можно использовать и с обычным Statement
а не только с PreparedStatement
)
Statement statement = conn.createStatement();
int updateCount = statement.executeUpdate("insert into x...)", Statement.RETURN_GENERATED_KEYS);
try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
if (generatedKeys.next()) {
return generatedKeys.getLong(1);
}
else {
throw new SQLException("Creating failed, no ID obtained.");
}
}
Ответ 9
В моем случае ->
ConnectionClass objConnectionClass=new ConnectionClass();
con=objConnectionClass.getDataBaseConnection();
pstmtGetAdd=con.prepareStatement(SQL_INSERT_ADDRESS_QUERY,Statement.RETURN_GENERATED_KEYS);
pstmtGetAdd.setString(1, objRegisterVO.getAddress());
pstmtGetAdd.setInt(2, Integer.parseInt(objRegisterVO.getCityId()));
int addId=pstmtGetAdd.executeUpdate();
if(addId>0)
{
ResultSet rsVal=pstmtGetAdd.getGeneratedKeys();
rsVal.next();
addId=rsVal.getInt(1);
}
Ответ 10
Если вы используете Spring JDBC, вы можете использовать класс Spring GeneratedKeyHolder для получения вставленного идентификатора.
Посмотрите этот ответ... Как получить вставленный идентификатор с помощью Spring Jdbctemplate.update(String sql, obj... args)
Ответ 11
Вы можете использовать следующий код Java, чтобы получить новый вставленный идентификатор.
ps = con.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, quizid);
ps.setInt(2, userid);
ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
if (rs.next()) {
lastInsertId = rs.getInt(1);
}
Ответ 12
Connection cn = DriverManager.getConnection("Host","user","pass");
Statement st = cn.createStatement("Ur Requet Sql");
int ret = st.execute();