Как получить идентификатор вставки в JDBC? - PullRequest
349 голосов
/ 16 декабря 2009

Я хочу INSERT запись в базе данных (в моем случае это Microsoft SQL Server) с использованием JDBC в Java В то же время я хочу получить идентификатор вставки. Как я могу добиться этого, используя JDBC API?

Ответы [ 12 ]

606 голосов
/ 16 декабря 2009

Если это автоматически сгенерированный ключ, вы можете использовать для этого Statement#getGeneratedKeys(). Вам нужно позвонить на тот же Statement, что и тот, который используется для INSERT. Сначала нужно , чтобы создать инструкцию, используя 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 относительно того, работает ли он. В настоящее время большинство последних версий будут работать, но, если я прав, драйвер JDBC Oracle все еще несколько проблематичен с этим. MySQL и DB2 уже поддерживали это целую вечность. PostgreSQL начал поддерживать его не так давно. Я не могу комментировать MSSQL, так как никогда не использовал его.

Для Oracle вы можете вызывать CallableStatement с предложением RETURNING или SELECT CURRVAL(sequencename) (или с любым специфичным для этого синтаксисом DB) непосредственно после INSERT в той же транзакции, чтобы получить последний сгенерированный ключ. Смотри также этот ответ .

15 голосов
/ 06 декабря 2016
  1. Создать сгенерированный столбец

    String generatedColumns[] = { "ID" };
    
  2. Передайте этот сгенерированный столбец вашему заявлению

    PreparedStatement stmtInsert = conn.prepareStatement(insertSQL, generatedColumns);
    
  3. Использование ResultSet объекта для извлечения GeneratedKeys для оператора

    ResultSet rs = stmtInsert.getGeneratedKeys();
    
    if (rs.next()) {
        long id = rs.getLong(1);
        System.out.println("Inserted ID -" + id); // display inserted record
    }
    
8 голосов
/ 24 июня 2011

Я запускаю 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/ - два других пока не нужны.

5 голосов
/ 14 декабря 2015

В соответствии с ошибкой «Неподдерживаемая функция» при использовании 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();

    }

Где BRANCHID - автоматически генерируемый идентификатор

3 голосов
/ 10 сентября 2013

Я использую 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.*; 

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)
        {
        }
    }
}

Это решение сработало для меня!

Надеюсь, это поможет!

1 голос
/ 21 мая 2019

Вы можете использовать следующий код 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);
                }
0 голосов
/ 25 января 2019

Если вы используете Spring JDBC, вы можете использовать класс Spring GeneratedKeyHolder для получения вставленного идентификатора.

Смотрите этот ответ ... Как получить вставленный идентификатор с помощью Spring Jdbctemplate.update (String sql, obj ... args)

0 голосов
/ 29 августа 2018

В моем случае ->

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);
}
0 голосов
/ 04 мая 2018

Можно использовать и с обычными 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.");
  }
}
0 голосов
/ 23 апреля 2018

С 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) выдают синтаксическую ошибку. После этого вы можете получить полученный идентификатор из списка (который обычно содержит ровно один элемент).

...