it-swarm.com.ru

Получение автоматически сгенерированного ключа от вставки строки весной 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 должен был быть вызван при вставке строки

Правка : 

Значение автоинкремента правильно создается при вставке строки

Любая идея ?

43
Jerec TheSith
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);
59
Artur

Самый простой способ получить ключ от INSERT с Spring JDBC - это использовать класс SimpleJdbcInsert. Вы можете увидеть пример в справочном руководстве Spring, в разделе, озаглавленном Получение автоматически сгенерированных ключей с использованием SimpleJdbcInsert .

22
Paul

Я использую 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: Получение автоматически сгенерированных ключей

10
xKommando

Решение с использованием 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();

Мне нравится это решение из-за NamedParameterJdbcTemplate, потому что параметры передаются по имени, а код более читабелен и менее подвержен ошибкам, особенно при больших запросах.

5
Vasile Bors

Кажется, есть некоторые известные проблемы с Keyholder и PostgreSQL. Посмотрите на обходной путь по этой ссылке Spring JDBC - последний вставленный идентификатор

Также проверьте таблицу базы данных напрямую, чтобы увидеть, правильно ли вставлена ​​запись (то есть с PK). Это поможет сузить проблему.

1
Kshitij

Взгляните на этот пост, особенно на принятый ответ об использовании синтаксиса INSERT ... RETURNING:

Как получить значение из последней вставленной строки?

Это лучший способ получить это значение в PostgreSQL, так как вы совершаете только одну обратную передачу по сети, и это выполняется как отдельная атомарная операция на сервере.

1
Matthew Wood

У меня была та же проблема, и оказалось, что мой идентификатор таблицы не был автоматически увеличен.

1
Eidan Spiegel

Я столкнулся с подобной проблемой. Я не знаю, почему именно я столкнулся с этой проблемой, но хорошо, что я должен решить эту проблему, используя следующий код:

final KeyHolder holder = new GeneratedKeyHolder();
int status = myTemplate.update(yourInsertSQL, namedParameters, holder, new String[]{"PrimaryKeyColumnName"});

Надеюсь, что это помогает кому-то.

1
AmitG
setGeneratedKeysColumnNames(new String[]{"column_name"});

Не забудьте установить имена для автоматически сгенерированных столбцов.

0
N. Osil