Respostas:
Se for uma chave gerada automaticamente, você poderá usá Statement#getGeneratedKeys()
-la. Você precisa chamá-lo da mesma Statement
forma que está sendo usado para o INSERT
. Você primeiro precisa criar a instrução usando Statement.RETURN_GENERATED_KEYS
para notificar o driver JDBC para retornar as chaves.
Aqui está um exemplo 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.");
}
}
}
}
Observe que você depende do driver JDBC para saber se ele funciona. Atualmente, a maioria das últimas versões funcionará, mas se eu estiver correto, o driver Oracle JDBC ainda é um pouco problemático. O MySQL e o DB2 já o suportam há séculos. O PostgreSQL começou a apoiá-lo há pouco tempo. Não posso comentar sobre o MSSQL como nunca o usei.
Para Oracle, você pode chamar a CallableStatement
com uma RETURNING
cláusula ou uma SELECT CURRVAL(sequencename)
(ou qualquer sintaxe específica do DB para fazer isso) diretamente após INSERT
a mesma transação para obter a última chave gerada. Veja também esta resposta .
generatedKeys.next()
retornos true
se o DB devolvida uma chave gerada. Olha, é um ResultSet
. O close()
é apenas para liberar recursos. Caso contrário, seu banco de dados ficará sem eles a longo prazo e seu aplicativo será interrompido. Você só precisa escrever algum método utilitário que execute a tarefa de fechamento. Veja também esta e esta resposta.
Criar coluna gerada
String generatedColumns[] = { "ID" };
Passe esta coluna geneada à sua declaração
PreparedStatement stmtInsert = conn.prepareStatement(insertSQL, generatedColumns);
Use o ResultSet
objeto para buscar as GeneratedKeys on Statement
ResultSet rs = stmtInsert.getGeneratedKeys();
if (rs.next()) {
long id = rs.getLong(1);
System.out.println("Inserted ID -" + id); // display inserted record
}
Estou acessando o Microsoft SQL Server 2008 R2 a partir de um aplicativo baseado em JDBC de thread único e retirando o último ID sem usar a propriedade RETURN_GENERATED_KEYS ou qualquer PreparedStatement. Parece algo assim:
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 postagem no blog isola bem três opções principais de "última identificação" do SQL Server: http://msjawahar.wordpress.com/2008/01/25/how-to-find-the-last-identity-value-inserted-in-the -sql-server / - ainda não precisou dos outros dois.
Ao encontrar um erro 'Recurso não suportado' durante o uso Statement.RETURN_GENERATED_KEYS
, tente o seguinte:
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();
}
Onde BATCHID
está o ID gerado automaticamente.
BATCHID
Estou usando o SQLServer 2008, mas tenho uma limitação de desenvolvimento: não consigo usar um novo driver, tenho que usar "com.microsoft.jdbc.sqlserver.SQLServerDriver" (não consigo usar "com.microsoft.sqlserver.jdbc .SQLServerDriver ").
É por isso que a solução conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)
lançou um java.lang.AbstractMethodError para mim. Nessa situação, uma solução possível que encontrei é a antiga sugerida pela Microsoft:
Como recuperar o valor @@ IDENTITY 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)
{
}
}
}
Esta solução funcionou para mim!
Eu espero que isso ajude!
Em vez de um comentário , só quero responder a postagem.
Interface java.sql.PreparedStatement
columnIndexes «Você pode usar a função prepareStatement que aceita columnIndexes e instrução SQL. Onde columnIndexes permitidos sinalizadores constantes são Statement.RETURN_GENERATED_KEYS 1 ou Statement.NO_GENERATED_KEYS [2], instrução SQL que pode conter um ou mais '?' Marcadores de parâmetro IN.
SYNTAX «
Connection.prepareStatement(String sql, int autoGeneratedKeys)
Connection.prepareStatement(String sql, int[] columnIndexes)
Exemplo:
PreparedStatement pstmt =
conn.prepareStatement( insertSQL, Statement.RETURN_GENERATED_KEYS );
columnNames « Liste os columnNames como 'id', 'uniqueID', ...
. na tabela de destino que contém as chaves geradas automaticamente que devem ser retornadas. O driver irá ignorá-los se a instrução SQL não for uma INSERT
instrução.
SYNTAX «
Connection.prepareStatement(String sql, String[] columnNames)
Exemplo:
String columnNames[] = new String[] { "id" };
PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
Exemplo 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();
}
}
Com o NativeQuery do Hibernate, você precisa retornar um ResultList em vez de um SingleResult, porque o Hibernate modifica uma consulta nativa
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id
gostar
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id LIMIT 1
se você tentar obter um único resultado, o que fará com que a maioria dos bancos de dados (pelo menos PostgreSQL) gere um erro de sintaxe. Depois, você pode buscar o ID resultante da lista (que geralmente contém exatamente um item).
É possível usá-lo com o normal Statement
também (não apenas 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.");
}
}
No meu 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 você estiver usando o Spring JDBC, poderá usar a classe GeneratedKeyHolder do Spring para obter o ID inserido.
Veja esta resposta ... Como obter a ID inserida 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
não espera nenhum parâmetro. 2. O execute
método de Statement
espera uma String com uma Consulta. 3. O execute
método retorna: true
se o primeiro resultado for um ResultSet
objeto; false
se é uma contagem de atualização ou não há 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); }