web-dev-qa-db-fra.com

Comment obtenir l'ID d'insertion dans JDBC?

Je veux INSERT un enregistrement dans une base de données (Microsoft SQL Server dans mon cas) à l'aide de JDBC en Java. Dans le même temps, je souhaite obtenir l’ID d’insertion. Comment puis-je atteindre cet objectif avec l'API JDBC?

358
Satya

S'il s'agit d'une clé générée automatiquement, vous pouvez utiliser Statement#getGeneratedKeys() pour cela. Vous devez l'appeler sur le même Statement que celui utilisé pour le INSERT. Vous devez d’abord créer l’instruction à l’aide de Statement.RETURN_GENERATED_KEYS afin d’aviser le pilote JDBC de renvoyer les clés.

Voici un exemple de base:

_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.");
            }
        }
    }
}
_

Notez que vous dépendez du pilote JDBC pour savoir s’il fonctionne. Actuellement, la plupart des dernières versions fonctionnent, mais si je ne me trompe pas, le pilote JDBC Oracle pose encore quelques problèmes. MySQL et DB2 le supportaient déjà depuis longtemps. PostgreSQL a commencé à le supporter il n'y a pas longtemps. Je ne peux pas commenter sur MSSQL car je ne l'ai jamais utilisé.

Pour Oracle, vous pouvez invoquer une CallableStatement avec une clause RETURNING ou une SELECT CURRVAL(sequencename) (ou toute autre syntaxe spécifique à la base de données) directement après la INSERT de la même transaction pour obtenir le dernier clé générée. Voir aussi cette réponse .

613
BalusC
  1. Transmettez cette colonne générée à votre relevé

    String generatedColumns[] = { "ID" };
    
  2. PreparedStatement stmtInsert = conn.prepareStatement(insertSQL, generatedColumns);

  3. Use ResultSet object to fetch the GeneratedKeys on Statement

    ResultSet rs = stmtInsert.getGeneratedKeys();
    
    if (rs.next()) {
        long id = rs.getLong(1);
        System.out.println("Inserted ID -" + id); // display inserted record
    }
    
17
Harsh Maheswari

J'utilise Microsoft SQL Server 2008 R2 à partir d'une application à une seule thread basée sur JDBC et je récupère le dernier ID sans utiliser la propriété RETURN_GENERATED_KEYS ni aucun autre document PreparedStatement. Ressemble à ceci:

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

Ce billet de blog isole joliment trois options principales de "dernier ID" de SQL Server: http://msjawahar.wordpress.com/2008/01/25/how-to-find-the-last-identity-value-inserted -in-the-sql-server / - n'a pas encore eu besoin des deux autres.

8
ftexperts

Selon l'erreur 'Fonctionnalité non prise en charge' avec Statement.RETURN_GENERATED_KEYS, essayez ceci:

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

    }

Où BRANCHID est l'identifiant généré automatiquement

5
Eitan Rimon

J'utilise SQLServer 2008, mais j'ai une limitation de développement: je ne peux pas utiliser de nouveau pilote, je dois utiliser "com.Microsoft. jdbc.sqlserver.SQLServerDriver "(je ne peux pas utiliser" com.Microsoft.sqlserver.jdbc.SQLServerDriver ").

C'est pourquoi la solution conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) a jeté pour moi un Java.lang.AbstractMethodError . Dans cette situation, une solution possible que j'ai trouvée est l'ancienne proposée par Microsoft: Comment récupérer la valeur @@ IDENTITY à l'aide de 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)
        {
        }
    }
}

Cette solution a fonctionné pour moi!

J'espère que ça aide!

3
xanblax

Avec NativeQuery d'Hibernate, vous devez renvoyer un ResultList au lieu d'un SingleResult, car Hibernate modifie une requête native.

INSERT INTO bla (a,b) VALUES (2,3) RETURNING id

comme

INSERT INTO bla (a,b) VALUES (2,3) RETURNING id LIMIT 1

si vous essayez d'obtenir un seul résultat, la plupart des bases de données (au moins PostgreSQL) génèrent une erreur de syntaxe. Ensuite, vous pouvez extraire l'identifiant résultant dans la liste (qui contient généralement exactement un élément).

0
Balin

Si vous utilisez Spring JDBC, vous pouvez utiliser la classe GeneratedKeyHolder de Spring pour obtenir l'ID inséré.

See this answer ... Comment obtenir un identifiant inséré avec Spring Jdbctemplate.update (String sql, obj ... args)

0
Rob Breidecker

Dans mon cas ->

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
TheSagya

Au lieu d'un commentaire , je veux juste répondre à un message.


Interface Java.sql.PreparedStatement

  1. columnIndexes "Vous pouvez utiliser la fonction prepareStatement qui accepte columnIndexes et une instruction SQL. Les indicateurs de constante autorisés pour columnIndexes sont Statement.RETURN_GENERATED_KEYS 1 ou Statement.NO_GENERATED_KEYS [2], instruction SQL pouvant contenir un ou plusieurs "?" Espaces réservés des paramètres IN.

    SYNTAX "

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

    Exemple:

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

  1. columnNames " Répertoriez les columnNames comme 'id', 'uniqueID', .... dans la table cible contenant les clés générées automatiquement à renvoyer. Le pilote les ignorera si l’instruction SQL n’est pas une instruction INSERT.

    SYNTAXE

    Connection.prepareStatement(String sql, String[] columnNames)
    

    Exemple:

    String columnNames[] = new String[] { "id" };
    PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
    

Exemple complet:

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();
    }
}
0
Yash

Il est également possible de l'utiliser avec les variables normales Statement (pas seulement 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
rogerdpack

Vous pouvez utiliser le code Java suivant pour obtenir le nouvel identifiant inséré.

                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
user11533210