PreparedStatement avec Statement.RETURN_GENERATED_KEYS

83

La seule façon pour certains pilotes JDBC de revenir Statement.RETURN_GENERATED_KEYSest d'effectuer l'une des opérations suivantes:

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);
}

Y a-t-il un moyen de faire la même chose avec PreparedStatement?


Éditer

La raison pour laquelle j'ai demandé si je pouvais faire de même avec PreparedStatementconsidérez le scénario suivant:

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

Dans le USERtableau, il y a un PRIMARY KEY (USER_ID)qui est un BIGINT AUTOINCREMENT(d'où la raison pour laquelle vous ne le voyez pas dans SQL_CREATEString.

Maintenant, je renseigne l' ?utilisation PreparedStatement.setXXXX(index, value). Je veux revenir ResultSet rs = PreparedStatement.getGeneratedKeys(). Comment puis-je atteindre cet objectif?

Buhake Sindi
la source
2
Beaucoup de gens comprennent mal et utilisent PreparedStatement # executeUpdate (arg). Java doc dit que This method with argument cannot be called on a PreparedStatement or CallableStatement.cela signifie que nous devons utiliser executeUpdate () sans argument même si la executeUpdate(arg)méthode peut être héritée dans la classe PreparedStatement mais nous n'avons pas à l'utiliser sinon nous obtiendrons SQLException.
AmitG

Réponses:

141

Vous pouvez soit utiliser la prepareStatementméthode en prenant un intparamètre supplémentaire

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

Pour certains pilotes JDBC (par exemple, Oracle), vous devez répertorier explicitement les noms de colonne ou les index des clés générées:

PreparedStatement ps = con.prepareStatement(sql, new String[]{"USER_ID"})
Jörn Horstmann
la source
J'ai accepté votre réponse car vous avez montré plus de façons d'obtenir le même résultat.
Buhake Sindi
67

Tu veux dire quelque chose comme ca?

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
la source
Comment l'ensemble de résultats des clés générées peut-il être nul?
AlikElzin-kilaka
10

N'ayant pas de compilateur par moi pour le moment, je répondrai en posant une question:

Avez-vous essayé cela? Est-ce que ça marche?

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);
}

Avertissement: de toute évidence, je n'ai pas compilé ceci, mais vous voyez l'idée.

PreparedStatement est une sous-interface de Statement , donc je ne vois pas pourquoi cela ne fonctionnerait pas, à moins que certains pilotes JDBC soient bogués.

darioo
la source
ce n'est pas ce que je recherche Je sais que PreparedStatementc'est une sous-classe de Statement.... voir mon post mis à jour.
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
la source
Si la clé est générée, la clé sinon la clé = 0 si elle n'est pas générée
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
la source
1
Ne devriez-vous pas libérer votre connexion dans le bloc finally, pas à l'extérieur (vous perdrez une connexion si vous obtenez une exception d'exécution de quelque nature que ce soit)?
Jules
@niraj - au lieu de ps.RETURN_GENERATED_KEYS, nous pouvons écrire Statement.RETURN_GENERATED_KEYS car il s'agit d'une variable statique dans la classe java.sql.Statement.
AmitG