Получение автоматически сгенерированного ключа из вставки строки в spring 3/PostgreSQL 8.4.9
Я хотел бы получить автоматически сгенерированный идентификатор из строки, но я получаю NullPointerException
Вот код:
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
И это таблица 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 поддерживает автоматически сгенерированные ключи, но я получаю это исключение:
java.lang.NullPointerException
at com.tante.db.JDBCUserAccountDAO.insertAccount(JDBCUserAccountDAO.java:72)
ИЗМЕНИТЬ:
Я попробовал это, чтобы получить автоматически сгенерированный ключ:
result = jdbcTemplate.queryForLong("select currval('compte_idcompte_seq')");
но я получаю PSQLException
:
the current value (currval) of the sequence compte_idcompte_seq is not defined in this session
, хотя я думал, что compte_idcompte_seq.NEXTVAL
должен был вызываться при вставке строки
ИЗМЕНИТЬ:
Значение автоматического увеличения равномерно создается при вставке строки
Любая идея?
Ответы
Ответ 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();
Обратите внимание, что в более новых версиях Postgres вам нужно использовать
connection.prepareStatement(sql.toString(),
new String[] { "idcompte" /* name of your id column */ })
вместо
connection.prepareStatement(sql.toString(),
Statement.RETURN_GENERATED_KEYS);
Ответ 2
Самый простой способ получить ключ от INSERT с помощью Spring JDBC - использовать класс SimpleJdbcInsert
. Вы можете увидеть пример в справочном руководстве Spring в разделе Извлечение сгенерированных автоматически ключей с помощью SimpleJdbcInsert.
Ответ 3
Я использую Spring3.1 + PostgreSQL9.1, и когда я использую этот
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();
Я получил это исключение:
org.springframework.dao.InvalidDataAccessApiUsageException:
The getKey method should only be used when a single key is returned.
The current key entry contains multiple keys: ...
Итак, я изменил на:
PreparedStatement ps =
connection.prepareStatement(youSQL, new String[]{"id"});
где "id" -
id serial not null primary key
И проблема решена. Поэтому я предположил, что используя
prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
здесь не так. Официальное руководство здесь, глава 13.2.8. Получение автоматически сгенерированных ключей
Ответ 4
Кажется, что есть некоторые известные проблемы с Keyholder и PostgreSQL. Посмотрите на обходной путь по этой ссылке Spring JDBC - Последний вставленный идентификатор
Также проверьте непосредственно таблицу базы данных, чтобы увидеть, правильно ли вставлена запись (т.е. с ПК). Это поможет сузить проблему.
Ответ 5
Взгляните на этот пост, особенно принятый ответ на использование синтаксиса INSERT... RETURNING:
Как получить значение из последней вставленной строки?
Это лучший способ получить это значение в PostgreSQL, поскольку вы делаете только одну поездку по сети, и это делается как одна атомная операция на сервере.
Ответ 6
Решение с использованием NamedParameterJdbcTemplate с 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();
Ответ 7
У меня была такая же проблема, и оказалось, что мой идентификатор таблицы не был автоматически увеличивался.
Ответ 8
Я столкнулся с подобной проблемой. Я не знаю, почему именно я столкнулся с этой проблемой, но хорошо, что мне нужно решить эту проблему, используя нижеприведенный код:
final KeyHolder holder = new GeneratedKeyHolder();
int status = myTemplate.update(yourInsertSQL, namedParameters, holder, new String[]{"PrimaryKeyColumnName"});
Надеюсь, что это поможет кому-то.