Je voudrais récupérer l'id généré automatiquement à partir d'une insertion de ligne, mais j'obtiens un NullPointerException
Voici le code:
long result = 0;
final String SQL = "INSERT INTO compte (prenom, nom, datenaissance, numtelephone) "
+ " VALUES(?,?,?,?)";
KeyHolder keyHolder = new GeneratedKeyHolder();
int row= this.jdbcTemplate.update(new PreparedStatementCreator(){
public PreparedStatement createPreparedStatement(Connection connection)
throws SQLException {
PreparedStatement ps =connection.prepareStatement(SQL);
ps.setString(1, a.getSurname());
ps.setString(2, a.getName());
ps.setDate(3, a.getDob());
ps.setString(4, a.getPhone());
return ps;
}
},keyHolder);
if (row > 0)
result = keyHolder.getKey().longValue(); //line 72
Et voici la table PostgreSQL:
CREATE TABLE compte
(
idcompte serial NOT NULL,
prenom character varying(25) NOT NULL,
nom character varying(25) NOT NULL,
datenaissance date NOT NULL,
numtelephone character varying(15) NOT NULL,
CONSTRAINT pk_compte PRIMARY KEY (idcompte )
);
PostgreSQL supporte les clés générées automatiquement, mais j'obtiens cette exception:
Java.lang.NullPointerException
at com.tante.db.JDBCUserAccountDAO.insertAccount(JDBCUserAccountDAO.Java:72)
EDIT: J'ai essayé ceci pour obtenir la clé générée automatiquement:
result = jdbcTemplate.queryForLong("select currval('compte_idcompte_seq')");
mais je reçois une PSQLException
:
the current value (currval) of the sequence compte_idcompte_seq is not defined in this session
, bien que je pensais que compte_idcompte_seq.NEXTVAL
.__ aurait dû être appelé lors de l'insertion de la ligne
MODIFIER :
La valeur d'auto-incrémentation est correctement créée lorsqu'une ligne est insérée
Une idée ?
KeyHolder holder = new GeneratedKeyHolder();
getJdbcTemplate().update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection connection)
throws SQLException {
PreparedStatement ps = connection.prepareStatement(sql.toString(),
Statement.RETURN_GENERATED_KEYS);
ps.setString(1, person.getUsername());
ps.setString(2, person.getPassword());
ps.setString(3, person.getEmail());
ps.setLong(4, person.getRole().getId());
return ps;
}
}, holder);
Long newPersonId = holder.getKey().longValue();
Notez que dans les nouvelles versions de Postgres, vous devez utiliser
connection.prepareStatement(sql.toString(),
new String[] { "idcompte" /* name of your id column */ })
au lieu de
connection.prepareStatement(sql.toString(),
Statement.RETURN_GENERATED_KEYS);
Le moyen le plus simple de récupérer une clé à partir d'un INSERT avec Spring JDBC consiste à utiliser la classe SimpleJdbcInsert
. Vous pouvez voir un exemple dans le manuel Spring Reference Guide, dans la section intitulée Récupération de clés générées automatiquement à l'aide de SimpleJdbcInsert .
J'utilise Spring3.1 + PostgreSQL9.1, et quand j'utilise ce
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(new PreparedStatementCreator() {
public PreparedStatement createPreparedStatement(Connection connection)
throws SQLException {
PreparedStatement ps =
connection.prepareStatement(youSQL,
Statement.RETURN_GENERATED_KEYS);
ps.setString(1, post.name_author);
...
return ps;
}
}, keyHolder);
long id = keyHolder.getKey().longValue();
J'ai cette exception:
org.springframework.dao.InvalidDataAccessApiUsageException:
The getKey method should only be used when a single key is returned.
The current key entry contains multiple keys: ...
Alors j'ai changé pour:
PreparedStatement ps =
connection.prepareStatement(youSQL, new String[]{"id"});
où "id" est
id serial not null primary key
Et le problème est résolu. Alors j'ai supposé qu'en utilisant
prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
n'est pas juste ici. Le guide officiel est ici , Chapitre 13.2.8: Récupération des clés générées automatiquement
Une solution utilisant NamedParameterJdbcTemplate avec Sequence.nextval:
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("prenom", prenom);
parameters.addValue("nom", nom);
parameters.addValue("datenaissance", datenaissance);
parameters.addValue("numtelephone", numtelephone);
final String SQL = "INSERT INTO compte (idcompte, prenom, nom, datenaissance, numtelephone) "
+ " VALUES(compte_idcompte_seq.NEXTVAL, :prenom, :nom, :datenaissance, :numtelephone)";
KeyHolder keyHolder = new GeneratedKeyHolder();
NamedParameterJdbcTemplate namedJdbcTemplate = new NamedParameterJdbcTemplate(txManager.getDataSource());
int nb = namedJdbcTemplate.update(SQL, parameters, keyHolder, new String[]{"idcompte"});
Long generatedId = keyHolder.getKey().longValue();
J'aime cette solution, car avec NamedParameterJdbcTemplate, les paramètres sont passés par nom et le code est plus lisible et moins sujet aux erreurs, en particulier lorsqu'il y a de grandes requêtes.
Il semble y avoir des problèmes connus avec Keyholder et PostgreSQL. Regardez la solution de contournement à ce lien Spring JDBC - Dernier inséré id
Vérifiez également la table de base de données directement pour voir si l’enregistrement est inséré correctement (c.-à-d. Avec PK). Cela aidera à réduire le problème.
Jetez un coup d'œil à ce billet, en particulier à la réponse acceptée en utilisant la syntaxe INSERT ... RETURNING:
Comment obtenir une valeur de la dernière ligne insérée?
C’est le meilleur moyen d’obtenir cette valeur dans PostgreSQL, car vous n’effectuez qu’un seul aller-retour sur le réseau, le tout en une seule opération atomique sur le serveur.
J'ai eu le même problème et il s'est avéré que mon identifiant de table n'était pas incrémenté automatiquement.
J'ai fait face au même problème. Je ne sais pas pourquoi je suis confronté à ce problème, mais je dois le résoudre en utilisant le code ci-dessous:
final KeyHolder holder = new GeneratedKeyHolder();
int status = myTemplate.update(yourInsertSQL, namedParameters, holder, new String[]{"PrimaryKeyColumnName"});
J'espère que ça aide quelqu'un.
setGeneratedKeysColumnNames(new String[]{"column_name"});
N'oubliez pas de définir les noms des colonnes générées automatiquement.