2012-05-15 4 views
39

vorrei recuperare l'id generato automaticamente da un inserimento di fila, ma ottengo un NullPointerExceptionOttenere generata automaticamente chiave dall'inserzione fila in primavera 3/PostgreSQL 8.4.9

Ecco il codice:

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 

E questa è la tabella di 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 supporta le chiavi generate automaticamente, ma ottengo questa eccezione:

java.lang.NullPointerException 
    at com.tante.db.JDBCUserAccountDAO.insertAccount(JDBCUserAccountDAO.java:72) 

EDIT: ho provato questo per ottenere l'auto generato chiave:

result = jdbcTemplate.queryForLong("select currval('compte_idcompte_seq')"); 

ma ottengo un PSQLException:

the current value (currval) of the sequence compte_idcompte_seq is not defined in this session, anche se ho pensato che compte_idcompte_seq.NEXTVAL avrebbe dovuto essere chiamato durante l'inserimento la riga

MODIFICA:

Il valore di incremento automatico viene creato correttamente quando si inserisce una riga

Qualche idea?

+1

sono curioso di sapere il numero di riga JDBCUserAccountDAO.java:72 – Kshitij

+0

Quale riga è la riga 72? Quale puntatore è nullo? –

+0

scusate, la riga 72 si riferisce a 'keyHolder.getKey(). LongValue()' –

risposta

53
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(); 

Si noti che nelle versioni più recenti di Postgres è necessario utilizzare

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

invece di

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

Lo sto codificando in un altro modo. Cercando di imparare dal tuo metodo ma continua a ricevere errore. Gentilmente aiuto: http://stackoverflow.com/questions/24567633/get-back-the-primary-key-value-after-insertion-to-db2-table-by-keyholder –

+1

Mi mancava la dichiarazione.RETURN_GENERATED_KEYS in la mia domanda. Aggiungendo questo ha funzionato. –

+0

Questo non sembra funzionare con HSQL (restituisce 'Questa funzione non è supportata') – maja

1

Sembra esserci qualche problema noto con Keyholder e PostgreSQL. Date un'occhiata alla soluzione alternativa a questo collegamento Spring JDBC - Last inserted id

Controllate anche la tabella del database direttamente per vedere se il record è inserito correttamente (cioè con PK). Questo aiuterà a restringere il problema.

1

Date un'occhiata a questo post, in particolare la risposta accettata di utilizzare l'INSERT ... Tornando sintassi:

How to get a value from the last inserted row?

questo il modo migliore per ottenere questo valore in PostgreSQL come si effettua una sola rete andata e ritorno e viene eseguito come una singola operazione atomica sul server.

+0

grazie! anche questo metodo funziona –

7

sto usando Spring3.1 + PostgreSQL9.1, e quando uso questo

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(); 

ho avuto questa eccezione:

org.springframework.dao.InvalidDataAccessApiUsageException: 
The getKey method should only be used when a single key is returned. 
The current key entry contains multiple keys: ... 

Così ho cambiato a:

PreparedStatement ps = 
connection.prepareStatement(youSQL, new String[]{"id"}); 

dove "id" è

id serial not null primary key 

E il problema è risolto. Così ho dovuto che l'utilizzo di

prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); 

non è proprio qui. La guida ufficiale è here, capitolo 13.2.8: Recupero auto-generate le chiavi

1

Una soluzione che utilizza 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(); 
1

Ho avuto lo stesso problema e si è scoperto che la mia identificazione tavolo era non incrementare automaticamente.

0

Ho affrontato il problema simile. Non so esattamente perché ho dovuto affrontare questo problema, ma cosa buona è ho avuto modo di risolvere questo utilizzando il codice qui sotto:

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

Speranza che aiuta qualcuno.