Java 在spring 3/PostgreSQL 8.4.9中从行插入获取自动生成的键

Java 在spring 3/PostgreSQL 8.4.9中从行插入获取自动生成的键,java,spring,postgresql,jdbc,auto-generate,Java,Spring,Postgresql,Jdbc,Auto Generate,我想从行插入中检索自动生成的id,但我得到一个NullPointerException 代码如下: long result = 0; final String SQL = "INSERT INTO compte (prenom, nom, datenaissance, numtelephone) " + " VALUES(?,?,?,?)"; KeyHolder keyHolder = new Generat

我想从行插入中检索自动生成的id,但我得到一个
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

序列compte_idcompte_seq的当前值(currval)在此会话中未定义
,尽管我认为
compte_idcompte_seq.NEXTVAL
插入行时应已调用

编辑:

插入行时会正确创建自动增量值


有什么想法吗?

钥匙套和PostgreSQL似乎存在一些已知的问题。请查看此链接的解决方法


还要直接检查数据库表以查看记录是否正确插入(即PK)。这将有助于缩小问题的范围。

看看这篇文章,特别是使用INSERT…RETURNING语法的公认答案:


这是在PostgreSQL中获取此值的最佳方法,因为您只需进行一次网络往返,并且它是作为服务器上的单个原子操作来完成的。

使用Spring JDBC从INSERT获取密钥的最简单方法是使用
SimpleJdbcInsert
类。您可以在《Spring参考指南》中标题为的部分中看到一个示例

请注意,在较新版本的Postgres中,您需要使用

connection.prepareStatement(sql.toString(), 
    new String[] { "idcompte" /* name of your id column */ })
而不是

connection.prepareStatement(sql.toString(), 
    Statement.RETURN_GENERATED_KEYS);

我使用的是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”在哪里

问题解决了。所以我想用

prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);

不在这里。官方指南是,第13.2.8章:检索自动生成的密钥

使用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是因为参数是按名称传递的,代码更可读,更不容易出错,特别是在有大的查询时。

我也遇到了同样的问题,结果证明我的表ID不是自动递增的。

我遇到了类似的问题。我不知道我为什么要面对这个问题,但好的是我可以通过使用以下代码来解决这个问题:

final KeyHolder holder = new GeneratedKeyHolder();
int status = myTemplate.update(yourInsertSQL, namedParameters, holder, new String[]{"PrimaryKeyColumnName"});
希望这能帮助别人

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

不要忘记设置自动生成列的名称。

我很想知道行号JDBCUserAccountDAO.java:72哪一行是第72行?哪一个指针是空的?对不起,第72行指的是
keyHolder.getKey().longValue()
,但是
keyHolder.getKeys().get(“idcompte”)
也是空的,所以有没有办法检索自动生成的密钥?我正在用另一种方式编码它。试着从你的方法中学习,但不要出错。请帮助:我缺少该语句。请在我的查询中返回\u生成的\u键。添加此功能使其正常工作。这似乎不适用于HSQL(它返回<代码>此函数不受支持<代码>),有没有办法在没有PreparedStatementCreator的情况下执行此操作?我对PreparedStatement有一些奇怪的问题。它不适用于mssql数据库
final KeyHolder holder = new GeneratedKeyHolder();
int status = myTemplate.update(yourInsertSQL, namedParameters, holder, new String[]{"PrimaryKeyColumnName"});
setGeneratedKeysColumnNames(new String[]{"column_name"});