java - pgconnection - Obtener la clave generada automáticamente desde la inserción de fila en el resorte 3/PostgreSQL 8.4.9
spring boot 2 postgresql (8)
Me gustaría recuperar el ID generado automáticamente desde una inserción de fila, pero obtengo una NullPointerException
Aquí está el código:
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
Y esta es la tabla de 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 admite claves generadas automáticamente, pero obtengo esta excepción:
java.lang.NullPointerException
at com.tante.db.JDBCUserAccountDAO.insertAccount(JDBCUserAccountDAO.java:72)
EDITAR: Intenté esto para obtener la clave generada automáticamente:
result = jdbcTemplate.queryForLong("select currval(''compte_idcompte_seq'')");
pero obtengo una PSQLException
:
the current value (currval) of the sequence compte_idcompte_seq is not defined in this session
, aunque pensé que se debería haber llamado compte_idcompte_seq.NEXTVAL
al insertar la fila
EDITAR:
El valor de autoincremento se crea correctamente cuando se inserta una fila
Alguna idea ?
Eche un vistazo a esta publicación, especialmente la respuesta aceptada de usar la sintaxis INSERTAR ... DEVOLVER:
¿Cómo obtener un valor de la última fila insertada?
Esta es la mejor manera de obtener este valor en PostgreSQL, ya que solo realiza una ida y vuelta de red y se realiza como una única operación atómica en el servidor.
Enfrenté el problema similar. No sé por qué exactamente enfrenté este problema, pero lo bueno es que tengo que resolver esto usando el siguiente código:
final KeyHolder holder = new GeneratedKeyHolder();
int status = myTemplate.update(yourInsertSQL, namedParameters, holder, new String[]{"PrimaryKeyColumnName"});
Espero que ayude a alguien.
Estoy usando Spring3.1 + PostgreSQL9.1, y cuando uso esto
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();
Tengo esta excepción:
org.springframework.dao.InvalidDataAccessApiUsageException:
The getKey method should only be used when a single key is returned.
The current key entry contains multiple keys: ...
Entonces cambié a:
PreparedStatement ps =
connection.prepareStatement(youSQL, new String[]{"id"});
donde "id" es
id serial not null primary key
Y el problema está resuelto. Así que supuse que usar
prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
no está aquí mismo La guía oficial está here , Capítulo 13.2.8: Recuperar claves autogeneradas
La forma más fácil de obtener una clave de un INSERT con Spring JDBC es usar la clase SimpleJdbcInsert
. Puede ver un ejemplo en la Guía de referencia de Spring, en la sección titulada Recuperando claves autogeneradas usando SimpleJdbcInsert .
Parece haber algunos problemas conocidos con Keyholder y PostgreSQL. Eche un vistazo a la solución en este enlace Spring JDBC - Último ID insertado
También verifique la tabla de la base de datos directamente para ver si el registro se insertó correctamente (es decir, con PK). Esto ayudará a reducir el problema.
Tuve el mismo problema y resultó que mi ID de tabla no se incrementaba automáticamente.
Una solución que usa NamedParameterJdbcTemplate con 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();
Me gusta esta solución debido a NamedParameterJdbcTemplate porque los parámetros se pasan por nombre y el código es más legible y menos propenso a errores, especialmente cuando hay grandes consultas.
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();
Tenga en cuenta que en las versiones más nuevas de Postgres debe usar
connection.prepareStatement(sql.toString(),
new String[] { "idcompte" /* name of your id column */ })
en lugar de
connection.prepareStatement(sql.toString(),
Statement.RETURN_GENERATED_KEYS);