Odpowiedzi:
Jeśli jest to klucz generowany automatycznie, możesz Statement#getGeneratedKeys()
do tego użyć . Musisz wywołać go tak samo, Statement
jak ten używany w INSERT
. Najpierw musisz utworzyć instrukcję za pomocąStatement.RETURN_GENERATED_KEYS
aby powiadomić sterownik JDBC o zwrocie kluczy.
Oto podstawowy przykład:
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.");
}
}
}
}
Pamiętaj, że zależy od sterownika JDBC, czy działa. Obecnie większość ostatnich wersji będzie działać, ale jeśli mam rację, sterownik Oracle JDBC nadal jest z tym nieco kłopotliwy. MySQL i DB2 już go obsługiwały od wieków. PostgreSQL zaczął go obsługiwać niedawno. Nie mogę komentować MSSQL, ponieważ nigdy go nie używałem.
Dla Oracle, można wywołać CallableStatement
z RETURNING
klauzulą lub SELECT CURRVAL(sequencename)
(lub cokolwiek DB-specyficznej składni, aby zrobić) bezpośrednio po INSERT
w tej samej transakcji do uzyskania ostatniego wygenerowanego klucza. Zobacz także tę odpowiedź .
generatedKeys.next()
powroty true
Jeżeli DB zwrócił wygenerowanego klucza. Spójrz, to jest ResultSet
. To close()
po prostu uwolnić zasoby. W przeciwnym razie w bazie danych zabraknie ich na dłuższą metę, a aplikacja ulegnie awarii. Musisz tylko napisać jakąś metodę narzędzia, która wykonuje zadanie zamykania. Zobacz także to i tę odpowiedź.
Utwórz kolumnę wygenerowaną
String generatedColumns[] = { "ID" };
Przekaż tę genowaną kolumnę do swojego oświadczenia
PreparedStatement stmtInsert = conn.prepareStatement(insertSQL, generatedColumns);
Użyj ResultSet
obiektu, aby pobrać GeneratedKeys na wyciągu
ResultSet rs = stmtInsert.getGeneratedKeys();
if (rs.next()) {
long id = rs.getLong(1);
System.out.println("Inserted ID -" + id); // display inserted record
}
Uderzam w Microsoft SQL Server 2008 R2 z jednowątkowej aplikacji opartej na JDBC i ściągam ostatni identyfikator bez użycia właściwości RETURN_GENERATED_KEYS lub jakiegokolwiek PreparedStatement. Wygląda mniej więcej tak:
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;
}
Ten post na blogu ładnie izoluje trzy główne opcje „ostatniego identyfikatora” programu SQL Server: http://msjawahar.wordpress.com/2008/01/25/how-to-find-the-last-identity-value-inserted-in-the -sql-server / - nie potrzebował jeszcze dwóch pozostałych.
W przypadku wystąpienia błędu „Nieobsługiwana funkcja” podczas korzystania Statement.RETURN_GENERATED_KEYS
, spróbuj wykonać następujące czynności:
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();
}
Gdzie BATCHID
jest automatycznie wygenerowany identyfikator.
BATCHID
Używam SQLServer 2008, ale mam ograniczenie programistyczne: nie mogę użyć do tego nowego sterownika, muszę użyć „com.microsoft.jdbc.sqlserver.SQLServerDriver” (nie mogę użyć „com.microsoft.sqlserver.jdbc .SQLServerDriver ”).
Właśnie dlatego rozwiązanie conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)
rzuciło mi java.lang.AbstractMethodError . W tej sytuacji możliwym rozwiązaniem, które znalazłem, jest stare sugerowane przez Microsoft:
Jak odzyskać @@ TOŻSAMOŚĆ Wartość za pomocą 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)
{
}
}
}
To rozwiązanie działało dla mnie!
Mam nadzieję, że to pomoże!
Możesz użyć następującego kodu java, aby uzyskać nowy wstawiony identyfikator.
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);
}
Zamiast komentarza chcę tylko odpowiedzieć na post.
Interfejs java.sql.PreparedStatement
columnIndexes «Możesz użyć funkcji preparStatement, która akceptuje kolumnęIndexes i instrukcję SQL. Tam, gdzie dozwolone są stałe kolumny columnIndexes, to Statement.RETURN_GENERATED_KEYS 1 lub Statement.NO_GENERATED_KEYS [2], instrukcja SQL, która może zawierać co najmniej jedno „?” Symbole zastępcze parametrów IN.
SKŁADNIA «
Connection.prepareStatement(String sql, int autoGeneratedKeys)
Connection.prepareStatement(String sql, int[] columnIndexes)
Przykład:
PreparedStatement pstmt =
conn.prepareStatement( insertSQL, Statement.RETURN_GENERATED_KEYS );
columnNames « Wymień kolumny, takie jak 'id', 'uniqueID', ...
. w tabeli docelowej zawierającej automatycznie wygenerowane klucze, które powinny zostać zwrócone. Sterownik je zignoruje, jeśli instrukcja SQL nie jest INSERT
instrukcją.
SKŁADNIA «
Connection.prepareStatement(String sql, String[] columnNames)
Przykład:
String columnNames[] = new String[] { "id" };
PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
Pełny przykład:
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();
}
}
Dzięki NativeQuery Hibernata musisz zwrócić ResultList zamiast SingleResult, ponieważ Hibernacja modyfikuje natywne zapytanie
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id
lubić
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id LIMIT 1
jeśli spróbujesz uzyskać pojedynczy wynik, który powoduje, że większość baz danych (przynajmniej PostgreSQL) zgłasza błąd składniowy. Następnie możesz pobrać wynikowy identyfikator z listy (która zwykle zawiera dokładnie jeden element).
Można go używać również z normalnymi Statement
(nie tylko 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.");
}
}
W moim przypadku ->
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);
}
Jeśli używasz Spring JDBC, możesz użyć klasy GeneratedKeyHolder Springa, aby uzyskać wstawiony identyfikator.
Zobacz tę odpowiedź ... Jak uzyskać wstawiony identyfikator za pomocą 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
Metoda Connection
nie przewiduje żadnych parametrów. 2. execute
Metoda od Statement
oczekuje ciągu z zapytaniem. 3. execute
Metoda zwraca: true
jeśli pierwszym wynikiem jest ResultSet
obiekt; false
jeśli jest to liczba aktualizacji lub nie ma żadnych wyników. 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); }