Respuestas:
Si se trata de una clave generada automáticamente, puede usarla Statement#getGeneratedKeys()
para esto. Debe llamarlo igual Statement
que el que se está utilizando para INSERT
. Primero debe crear la declaración utilizando Statement.RETURN_GENERATED_KEYS
para notificar al controlador JDBC que devuelva las claves.
Aquí hay un ejemplo básico:
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.");
}
}
}
}
Tenga en cuenta que depende del controlador JDBC para saber si funciona. Actualmente, la mayoría de las últimas versiones funcionarán, pero si estoy en lo cierto, el controlador Oracle JDBC sigue siendo un poco problemático con esto. MySQL y DB2 ya lo soportaron por años. PostgreSQL comenzó a admitirlo no hace mucho tiempo. No puedo comentar sobre MSSQL ya que nunca lo he usado.
Para Oracle, puede invocar a CallableStatement
con una RETURNING
cláusula o un SELECT CURRVAL(sequencename)
(o cualquier sintaxis específica de DB para hacerlo) directamente después INSERT
de la misma transacción para obtener la última clave generada. Ver también esta respuesta .
generatedKeys.next()
rendimientos true
si el DB devolvió una clave generada. Mira, es un ResultSet
. El close()
es solo para liberar recursos. De lo contrario, su base de datos se quedará sin ellos a largo plazo y su aplicación se romperá. Solo tiene que escribir algún método de utilidad que haga la tarea de cierre. Vea también esto y esta respuesta.
Crear columna generada
String generatedColumns[] = { "ID" };
Pase esta columna generada a su estado de cuenta
PreparedStatement stmtInsert = conn.prepareStatement(insertSQL, generatedColumns);
Use el ResultSet
objeto para obtener las claves generadas en la instrucción
ResultSet rs = stmtInsert.getGeneratedKeys();
if (rs.next()) {
long id = rs.getLong(1);
System.out.println("Inserted ID -" + id); // display inserted record
}
Estoy accediendo a Microsoft SQL Server 2008 R2 desde una aplicación basada en JDBC de un solo subproceso y retirando el último ID sin usar la propiedad RETURN_GENERATED_KEYS o cualquier PreparedStatement. Se ve algo como esto:
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;
}
Esta publicación de blog aísla muy bien tres opciones principales de "último ID" de SQL Server: http://msjawahar.wordpress.com/2008/01/25/how-to-find-the-last-identity-value-inserted-in-the -sql-server / - aún no he necesitado los otros dos.
Cuando encuentre un error de 'Función no compatible' mientras lo usa Statement.RETURN_GENERATED_KEYS
, intente esto:
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();
}
¿Dónde BATCHID
está la identificación generada automáticamente?
BATCHID
Estoy usando SQLServer 2008, pero tengo una limitación de desarrollo: no puedo usar un nuevo controlador, tengo que usar "com.microsoft.jdbc.sqlserver.SQLServerDriver" (No puedo usar "com.microsoft.sqlserver.jdbc .SQLServerDriver ").
Es por eso que la solución conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)
arrojó un java.lang.AbstractMethodError para mí. En esta situación, una posible solución que encontré es la anterior sugerida por Microsoft:
Cómo recuperar el valor de @@ IDENTITY utilizando 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)
{
}
}
}
¡Esta solución funcionó para mí!
¡Espero que esto ayude!
En lugar de un comentario , solo quiero responder la publicación.
Interfaz java.sql.PreparedStatement
columnIndexes «Puede usar la función prepareStatement que acepta columnIndexes y la declaración SQL. Donde columnIndexes permitieron indicadores constantes son Statement.RETURN_GENERATED_KEYS 1 o Statement.NO_GENERATED_KEYS [2], instrucción SQL que puede contener uno o más '?' Marcadores de posición de parámetros IN.
SINTAXIS «
Connection.prepareStatement(String sql, int autoGeneratedKeys)
Connection.prepareStatement(String sql, int[] columnIndexes)
Ejemplo:
PreparedStatement pstmt =
conn.prepareStatement( insertSQL, Statement.RETURN_GENERATED_KEYS );
columnNames « Listar los columnNames como 'id', 'uniqueID', ...
. en la tabla de destino que contiene las claves generadas automáticamente que deben devolverse. El controlador los ignorará si la declaración SQL no es una INSERT
declaración.
SINTAXIS «
Connection.prepareStatement(String sql, String[] columnNames)
Ejemplo:
String columnNames[] = new String[] { "id" };
PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
Ejemplo 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();
}
}
Puede usar el siguiente código Java para obtener una nueva identificación insertada.
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 de Hibernate, debe devolver una lista de resultados en lugar de un resultado único, porque Hibernate modifica una consulta nativa
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id
me gusta
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id LIMIT 1
si intenta obtener un único resultado, lo que hace que la mayoría de las bases de datos (al menos PostgreSQL) arrojen un error de sintaxis. Luego, puede buscar la identificación resultante de la lista (que generalmente contiene exactamente un elemento).
Es posible usarlo también con normales Statement
(no 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.");
}
}
En mi 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);
}
Si está utilizando Spring JDBC, puede utilizar la clase GeneratedKeyHolder de Spring para obtener la ID insertada.
Vea esta respuesta ... Cómo insertar la identificación 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
método de Connection
no espere ningún parámetro. 2. El execute
método de Statement
espera una cadena con una consulta. 3. El execute
método devuelve: true
si el primer resultado es un ResultSet
objeto; false
si es un recuento de actualizaciones o no hay resultados. 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); }