问题
I would like to retrieve the auto-generated id from a row insertion, but I get a NullPointerException
Here is the 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
And this is the PostgreSQL table :
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 supports auto-generated keys, but I get this exception :
java.lang.NullPointerException
at com.tante.db.JDBCUserAccountDAO.insertAccount(JDBCUserAccountDAO.java:72)
EDIT : I tried this to get the auto generated key :
result = jdbcTemplate.queryForLong("select currval('compte_idcompte_seq')");
but I get a PSQLException
:
the current value (currval) of the sequence compte_idcompte_seq is not defined in this session
, although I thought that compte_idcompte_seq.NEXTVAL
should have been called when inserting the row
EDIT :
The auto-increment value is properly created when a row is inserted
Any idea ?
回答1:
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();
Note that in newer versions of Postgres you need to use
connection.prepareStatement(sql.toString(),
new String[] { "idcompte" /* name of your id column */ })
instead of
connection.prepareStatement(sql.toString(),
Statement.RETURN_GENERATED_KEYS);
回答2:
The easiest way to get a key back from an INSERT with Spring JDBC is to use the SimpleJdbcInsert
class. You can see an example in the Spring Reference Guide, in the section titled Retrieving auto-generated keys using SimpleJdbcInsert.
回答3:
I'm using Spring3.1 + PostgreSQL9.1, and when I use this
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();
I got this 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: ...
So I changed to :
PreparedStatement ps =
connection.prepareStatement(youSQL, new String[]{"id"});
where "id" is
id serial not null primary key
And the problem is solved. So I supposed that using
prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
is not right here. The official guide is here, Chapter 13.2.8 :Retrieving auto-generated keys
回答4:
A solution using NamedParameterJdbcTemplate with 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();
I like this solution because with NamedParameterJdbcTemplate because the parameters are passed by name and the code is more readable and less prone to errors, especially when there are big queries.
回答5:
There seems to be some known issues with Keyholder and PostgreSQL. Have a look at the workaround at this link Spring JDBC - Last inserted id
Also do check the database table directly to see if the record is inserted properly(i.e with PK). This will help to narrow down the problem.
回答6:
Take a look at this post, especially the accepted answer of using the INSERT...RETURNING syntax:
How to get a value from the last inserted row?
This the best way to get this value in PostgreSQL as you only make one network round trip and it's done as a single atomic operation on the server.
回答7:
I had the same problem and it turned out that my table ID was not auto incrementing.
回答8:
I faced the similar problem. I do not know why exactly I faced this problem but good thing is I got to resolve this by using below code:
final KeyHolder holder = new GeneratedKeyHolder();
int status = myTemplate.update(yourInsertSQL, namedParameters, holder, new String[]{"PrimaryKeyColumnName"});
Hope that helps someone.
回答9:
setGeneratedKeysColumnNames(new String[]{"column_name"});
Don't forget to set the names for the auto-generated columns.
来源:https://stackoverflow.com/questions/10597477/getting-auto-generated-key-from-row-insertion-in-spring-3-postgresql-8-4-9