PreparedStatement with Statement.RETURN_GENERATED_KEYS

83

Jedynym sposobem powrotu niektórych sterowników JDBC Statement.RETURN_GENERATED_KEYSjest wykonanie następujących czynności:

long key = -1L;
Statement statement = connection.createStatement();
statement.executeUpdate(YOUR_SQL_HERE, Statement.RETURN_GENERATED_KEYS);
ResultSet rs = statement.getGeneratedKeys();
if (rs != null && rs.next()) {
    key = rs.getLong(1);
}

Czy jest sposób, aby zrobić to samo PreparedStatement?


Edytować

Powód, dla którego zapytałem, czy mogę zrobić to samo, PreparedStatementrozważ następujący scenariusz:

private static final String SQL_CREATE = 
            "INSERT INTO
            USER(FIRST_NAME, MIDDLE_NAME, LAST_NAME, EMAIL_ADDRESS, DOB) 
            VALUES (?, ?, ?, ?, ?)";

W USERtabeli znajduje się PRIMARY KEY (USER_ID)który to a BIGINT AUTOINCREMENT(dlatego nie widzisz go w SQL_CREATEString.

Teraz wypełniam plik ?using PreparedStatement.setXXXX(index, value). Chcę wrócić ResultSet rs = PreparedStatement.getGeneratedKeys(). Jak mogę to osiągnąć?

Buhake Sindi
źródło
2
Wiele osób źle rozumie i używa PreparedStatement # executeUpdate (arg). This method with argument cannot be called on a PreparedStatement or CallableStatement.Dokument Java mówi, że oznacza to, że musimy używać funkcji executeUpdate () bez argumentów, mimo że executeUpdate(arg)metoda może być dziedziczona w klasie PreparedStatement, ale nie musimy jej używać, w przeciwnym razie otrzymamy SQLException.
AmitG

Odpowiedzi:

143

Możesz użyć prepareStatementmetody pobierającej dodatkowy intparametr

PreparedStatement ps = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)

W przypadku niektórych sterowników JDBC (na przykład Oracle) musisz jawnie podać nazwy kolumn lub indeksy wygenerowanych kluczy:

PreparedStatement ps = con.prepareStatement(sql, new String[]{"USER_ID"})
Jörn Horstmann
źródło
Zaakceptowałem twoją odpowiedź, ponieważ pokazałeś więcej sposobów na osiągnięcie tego samego wyniku.
Buhake Sindi
67

Masz na myśli coś takiego?

long key = -1L;

PreparedStatement preparedStatement = connection.prepareStatement(YOUR_SQL_HERE, PreparedStatement.RETURN_GENERATED_KEYS);
preparedStatement.setXXX(index, VALUE);
preparedStatement.executeUpdate();

ResultSet rs = preparedStatement.getGeneratedKeys();

if (rs.next()) {
    key = rs.getLong(1);
}
nanda
źródło
W jaki sposób zestaw wyników wygenerowanych kluczy może być pusty?
AlikElzin-kilaka
10

Nie mając teraz kompilatora, odpowiem zadając pytanie:

Czy próbowałeś tego? Czy to działa?

long key = -1L;
PreparedStatement statement = connection.prepareStatement();
statement.executeUpdate(YOUR_SQL_HERE, PreparedStatement.RETURN_GENERATED_KEYS);
ResultSet rs = statement.getGeneratedKeys();
if (rs != null && rs.next()) {
    key = rs.getLong(1);
}

Zastrzeżenie: Oczywiście nie skompilowałem tego, ale masz pomysł.

PreparedStatement jest podinterfejsem Statement , więc nie widzę powodu, dla którego to nie zadziałałoby, chyba że niektóre sterowniki JDBC zawierają błędy.

darioo
źródło
nie tego szukam Wiem, że PreparedStatementjest to podklasa Statement… zobacz mój zaktualizowany post.
Buhake Sindi
2
String query = "INSERT INTO ....";
PreparedStatement preparedStatement = connection.prepareStatement(query, PreparedStatement.RETURN_GENERATED_KEYS);

preparedStatement.setXXX(1, VALUE); 
preparedStatement.setXXX(2, VALUE); 
....
preparedStatement.executeUpdate();  

ResultSet rs = preparedStatement.getGeneratedKeys();  
int key = rs.next() ? rs.getInt(1) : 0;

if(key!=0){
    System.out.println("Generated key="+key);
}
Dharmendrasinh Chudasama
źródło
Jeśli klucz generowany następnie kluczowych inaczej kluczowe = 0, jeśli nie został wygenerowany
Dharmendrasinh Chudasama
0
private void alarmEventInsert(DriveDetail driveDetail, String vehicleRegNo, int organizationId) {

    final String ALARM_EVENT_INS_SQL = "INSERT INTO alarm_event (event_code,param1,param2,org_id,created_time) VALUES (?,?,?,?,?)";
    CachedConnection conn = JDatabaseManager.getConnection();
    PreparedStatement ps = null;
    ResultSet generatedKeys = null;
    try {
        ps = conn.prepareStatement(ALARM_EVENT_INS_SQL, ps.RETURN_GENERATED_KEYS);
        ps.setInt(1, driveDetail.getEventCode());
        ps.setString(2, vehicleRegNo);
        ps.setString(3, null);
        ps.setInt(4, organizationId);
        ps.setString(5, driveDetail.getCreateTime());
        ps.execute();
        generatedKeys = ps.getGeneratedKeys();
        if (generatedKeys.next()) {
            driveDetail.setStopDuration(generatedKeys.getInt(1));
        }
    } catch (SQLException e) {
        e.printStackTrace();
        logger.error("Error inserting into alarm_event : {}", e
                .getMessage());
        logger.info(ps.toString());
    } finally {
        if (ps != null) {
            try {

                if (ps != null)
                    ps.close();
            } catch (SQLException e) {
                logger.error("Error closing prepared statements : {}", e
                        .getMessage());
            }
        }
    }
    JDatabaseManager.freeConnection(conn);
}
niraj
źródło
1
Czy nie powinieneś uwalniać połączenia w ostatnim bloku, a nie poza nim (jeśli dostaniesz jakiś wyjątek w czasie wykonywania, przesuniesz połączenie)?
Jules,
@niraj - zamiast ps.RETURN_GENERATED_KEYS możemy napisać Statement.RETURN_GENERATED_KEYS, ponieważ jest to zmienna statyczna w klasie java.sql.Statement.
AmitG,