Risposte:
Se si tratta di una chiave generata automaticamente, è possibile utilizzarla Statement#getGeneratedKeys()
per questo. È necessario chiamarlo allo stesso modo Statement
di quello utilizzato per il INSERT
. È innanzitutto necessario creare l'istruzione utilizzando Statement.RETURN_GENERATED_KEYS
per notificare al driver JDBC di restituire le chiavi.
Ecco un esempio di 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.");
}
}
}
}
Si noti che si dipende dal driver JDBC sul funzionamento. Attualmente, la maggior parte delle ultime versioni funzionerà, ma se ho ragione, il driver Oracle JDBC è ancora un po 'problematico con questo. MySQL e DB2 lo supportano già da anni. PostgreSQL ha iniziato a supportarlo non molto tempo fa. Non posso commentare MSSQL perché non l'ho mai usato.
Per Oracle, è possibile richiamare a CallableStatement
con una RETURNING
clausola o una SELECT CURRVAL(sequencename)
(o qualunque sintassi specifica del DB per farlo) direttamente dopo INSERT
la stessa transazione per ottenere l'ultima chiave generata. Vedi anche questa risposta .
generatedKeys.next()
rendimenti true
se il DB restituito una chiave generata. Guarda, è un ResultSet
. Il close()
è solo per liberare risorse. Altrimenti il tuo DB si esaurirà a lungo termine e l'applicazione si interromperà. Devi solo scrivere tu stesso un metodo di utilità che fa il compito di chiusura. Vedi anche questa e questa risposta.
Crea colonna generata
String generatedColumns[] = { "ID" };
Passa questa colonna modificata alla tua dichiarazione
PreparedStatement stmtInsert = conn.prepareStatement(insertSQL, generatedColumns);
Utilizzare l' ResultSet
oggetto per recuperare l'istruzione GeneratedKeys on
ResultSet rs = stmtInsert.getGeneratedKeys();
if (rs.next()) {
long id = rs.getLong(1);
System.out.println("Inserted ID -" + id); // display inserted record
}
Sto colpendo Microsoft SQL Server 2008 R2 da un'applicazione basata su JDBC a thread singolo e sto ritirando l'ultimo ID senza utilizzare la proprietà RETURN_GENERATED_KEYS o qualsiasi PreparedStatement. Sembra qualcosa del genere:
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;
}
Questo post sul blog isola tre opzioni principali dell'ultimo ID di SQL Server: http://msjawahar.wordpress.com/2008/01/25/how-to-find-the-last-identity-value-inserted-in-the -sql-server / - non sono ancora necessari gli altri due.
Quando si verifica un errore "Funzionalità non supportata" durante l'utilizzo Statement.RETURN_GENERATED_KEYS
, provare questo:
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();
}
Dove si BATCHID
trova l'id generato automaticamente.
BATCHID
Sto usando SQLServer 2008, ma ho un limite di sviluppo: non posso usare un nuovo driver per questo, devo usare "com.microsoft.jdbc.sqlserver.SQLServerDriver" (non posso usare "com.microsoft.sqlserver.jdbc .SQLServerDriver ").
Ecco perché la soluzione ha conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)
lanciato un java.lang.AbstractMethodError per me. In questa situazione, una possibile soluzione che ho trovato è quella suggerita da Microsoft:
Come recuperare il valore di IDENTITÀ @@ usando 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)
{
}
}
}
Questa soluzione ha funzionato per me!
Spero che questo possa essere d'aiuto!
Invece di un commento , voglio solo rispondere al post.
Interfaccia java.sql.PreparedStatement
columnIndexes «È possibile utilizzare la funzione PreparStatement che accetta columnIndexes e l'istruzione SQL. Dove columnIndexes sono ammessi flag costanti sono Statement.RETURN_GENERATED_KEYS 1 o Statement.NO_GENERATED_KEYS [2], istruzione SQL che può contenere uno o più '?' Segnaposto parametro IN.
SINTASSI «
Connection.prepareStatement(String sql, int autoGeneratedKeys)
Connection.prepareStatement(String sql, int[] columnIndexes)
Esempio:
PreparedStatement pstmt =
conn.prepareStatement( insertSQL, Statement.RETURN_GENERATED_KEYS );
columnNames « Elenca i columnNames come 'id', 'uniqueID', ...
. nella tabella di destinazione che contiene le chiavi generate automaticamente che devono essere restituite. Il driver li ignorerà se l'istruzione SQL non è INSERT
un'istruzione.
SINTASSI «
Connection.prepareStatement(String sql, String[] columnNames)
Esempio:
String columnNames[] = new String[] { "id" };
PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
Esempio completo:
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();
}
}
È possibile utilizzare il seguente codice Java per ottenere il nuovo ID inserito.
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);
}
Con NativeQuery di Hibernate, è necessario restituire un ResultList anziché un SingleResult, poiché Hibernate modifica una query nativa
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id
piace
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id LIMIT 1
se si tenta di ottenere un singolo risultato, ciò causa la maggior parte dei database (almeno PostgreSQL) che genera un errore di sintassi. Successivamente, è possibile recuperare l'id risultante dall'elenco (che di solito contiene esattamente un elemento).
È possibile usarlo anche con quelli normali Statement
(non solo 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.");
}
}
Nel mio caso ->
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);
}
Se si utilizza Spring JDBC, è possibile utilizzare la classe GeneratedKeyHolder di Spring per ottenere l'ID inserito.
Vedi questa risposta ... Come ottenere l'id inserito usando 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
metodo da Connection
non prevede parametri. 2. Il execute
metodo Statement
prevede una stringa con una query. 3. Il execute
metodo restituisce: true
se il primo risultato è un ResultSet
oggetto; false
se è un conteggio degli aggiornamenti o non ci sono risultati. 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); }