Réponses:
S'il s'agit d'une clé générée automatiquement, vous pouvez l'utiliser Statement#getGeneratedKeys()
pour cela. Vous devez l'appeler de la même manière Statement
que celle utilisée pour le INSERT
. Vous devez d' abord créer l'instruction à l'aide de Statement.RETURN_GENERATED_KEYS
pour informer le pilote JDBC de retourner 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 fonctionneront, mais si je ne me trompe pas, le pilote Oracle JDBC est toujours quelque peu gênant avec cela. MySQL et DB2 le supportaient déjà depuis des lustres. PostgreSQL a commencé à le prendre en charge il n'y a pas longtemps. Je ne peux pas commenter MSSQL car je ne l'ai jamais utilisé.
Pour Oracle, vous pouvez appeler un CallableStatement
avec une RETURNING
clause ou un SELECT CURRVAL(sequencename)
(ou la syntaxe spécifique à DB pour ce faire) directement après la INSERT
dans la même transaction pour obtenir la dernière clé générée. Voir aussi cette réponse .
generatedKeys.next()
renvoie true
si la base de données a renvoyé une clé générée. Regardez, c'est un ResultSet
. Il close()
s'agit simplement de libérer des ressources. Sinon, votre base de données en manquera à long terme et votre application se cassera. Vous n'avez qu'à écrire vous-même une méthode utilitaire qui fait la tâche de fermeture. Voir aussi ceci et cette réponse.
Créer une colonne générée
String generatedColumns[] = { "ID" };
Passez cette colonne créée à votre déclaration
PreparedStatement stmtInsert = conn.prepareStatement(insertSQL, generatedColumns);
Utiliser un ResultSet
objet pour récupérer les GeneratedKeys on Statement
ResultSet rs = stmtInsert.getGeneratedKeys();
if (rs.next()) {
long id = rs.getLong(1);
System.out.println("Inserted ID -" + id); // display inserted record
}
Je frappe Microsoft SQL Server 2008 R2 à partir d'une application basée sur JDBC à un seul thread et je récupère le dernier ID sans utiliser la propriété RETURN_GENERATED_KEYS ou tout 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-insert-in-the -sql-server / - n'a pas encore eu besoin des deux autres.
Lorsque vous rencontrez une erreur «Fonction non prise en charge» lors de l'utilisation 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ù BATCHID
est l'ID généré automatiquement.
BATCHID
J'utilise SQLServer 2008, mais j'ai une limitation de développement: je ne peux pas utiliser un nouveau pilote pour cela, je dois utiliser "com.microsoft.jdbc.sqlserver.SQLServerDriver" (je ne peux pas utiliser "com.microsoft.sqlserver.jdbc .SQLServerDriver ").
C'est pourquoi la solution a conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)
lancé une java.lang.AbstractMethodError pour moi. Dans cette situation, une solution possible que j'ai trouvée est l'ancienne suggéré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!
Au lieu d'un commentaire , je veux juste répondre à un post.
Interface java.sql.PreparedStatement
columnIndexes «Vous pouvez utiliser la fonction prepareStatement qui accepte columnIndexes et l'instruction SQL. Où les indicateurs de colonnes autorisés de columnIndexes sont Statement.RETURN_GENERATED_KEYS 1 ou Statement.NO_GENERATED_KEYS [2], instruction SQL pouvant contenir un ou plusieurs '?' Espaces réservés pour les 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 );
columnNames « Liste les noms de colonnes comme 'id', 'uniqueID', ...
. dans la table cible contenant les clés générées automatiquement qui doivent être renvoyées. Le pilote les ignorera si l'instruction SQL n'est pas une INSERT
instruction.
SYNTAX «
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();
}
}
Vous pouvez utiliser le code java suivant pour obtenir un 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);
}
Avec NativeQuery d'Hibernate, vous devez renvoyer une 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, ce qui provoque la plupart des bases de données (au moins PostgreSQL) à lancer une erreur de syntaxe. Ensuite, vous pouvez récupérer l'ID résultant de la liste (qui contient généralement exactement un élément).
Il est possible de l'utiliser aussi avec des 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.");
}
}
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);
}
Si vous utilisez Spring JDBC, vous pouvez utiliser la classe GeneratedKeyHolder de Spring pour obtenir l'ID inséré.
Voir cette réponse ... Comment obtenir un identifiant inséré à l'aide de Spring Jdbctemplate.update (String sql, obj ... args)
Connection cn = DriverManager.getConnection("Host","user","pass");
Statement st = cn.createStatement("Ur Requet Sql");
int ret = st.execute();
createStatement
méthode de Connection
n'attend aucun paramètre. 2. La execute
méthode from Statement
attend une chaîne avec une requête. 3. La execute
méthode renvoie: true
si le premier résultat est un ResultSet
objet; false
s'il s'agit d'un nombre de mises à jour ou s'il n'y a aucun résultat. 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); }