Как получить идентификатор вставки в JDBC?

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

10 ответов


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

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


  1. Создать Созданный Столбец

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

    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
    }
    

Я нажимаю 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 "last ID" : http://msjawahar.wordpress.com/2008/01/25/how-to-find-the-last-identity-value-inserted-in-the-sql-server/


в соответствии с ошибкой "неподдерживаемая функция" с использованием 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-автоматически сгенерированный id


Я использую SQLServer 2008, но у меня есть ограничение развития: я не могу использовать новый драйвер для него, я должен использовать "com.Microsoft.интерфейс jdbc.от SQLServer.SQLServerDriver "(я не могу использовать " com.Microsoft.от SQLServer.интерфейс jdbc.SQLServerDriver").

вот почему решение conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) бросил java.ленг.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)
        {
        }
    }
}

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

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


вместо комментарий, Я просто хочу ответить на пост.


интерфейс java.язык SQL.Объект PreparedStatement

  1. columnIndexes " можно использовать функцию prepareStatement, которая принимает columnIndexes и инструкцию SQL. где columnIndexes постоянному флаги заявлении.RETURN_GENERATED_KEYS1 или заявление.NO_GENERATED_KEYS[2], SQL утверждение, которое может содержать один или несколько"? В местозаполнителей.

    синтаксис "

    Connection.prepareStatement(String sql, int autoGeneratedKeys)
    Connection.prepareStatement(String sql, int[] columnIndexes)
    

    пример:

    PreparedStatement pstmt = 
        conn.prepareStatement( insertSQL, Statement.RETURN_GENERATED_KEYS );
    

  1. columnNames " список из columnNames как '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();
    }
}

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


можно использовать его с normal 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.");
  }
}

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

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

Connection cn = DriverManager.getConnection("Host","user","pass");
Statement st = cn.createStatement("Ur Requet Sql");
int ret  = st.execute();