wake-up-neo.com

Automatisch generierten Schlüssel aus der Zeileneinfügung im Frühjahr erhalten 3/PostgreSQL 8.4.9

Ich möchte die automatisch generierte ID aus einer Zeileneinfügung abrufen, erhalte jedoch eine NullPointerException

Hier ist der 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

Und das ist die PostgreSQL-Tabelle:

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 unterstützt automatisch generierte Schlüssel, aber ich bekomme diese Ausnahme:

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

EDIT: Ich habe dies versucht, um den automatisch generierten Schlüssel zu erhalten:

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

aber ich bekomme eine PSQLException

the current value (currval) of the sequence compte_idcompte_seq is not defined in this session, obwohl ich dachte, dass compte_idcompte_seq.NEXTVAL beim Einfügen der Zeile hätte aufgerufen werden sollen

BEARBEITEN: 

Der Auto-Inkrement-Wert wird ordnungsgemäß erstellt, wenn eine Zeile eingefügt wird

Irgendeine Idee ?

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

Beachten Sie, dass Sie in neueren Versionen von Postgres verwenden müssen 

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

anstatt 

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

Der einfachste Weg, um einen Schlüssel von einem INSERT mit Spring JDBC zurückzubekommen, ist die Verwendung der Klasse SimpleJdbcInsert. Ein Beispiel finden Sie im Spring-Referenzhandbuch im Abschnitt Automatisch erzeugte Schlüssel mit SimpleJdbcInsert abrufen.

22
Paul

Ich verwende Spring3.1 + PostgreSQL9.1, und wenn ich dies verwende

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

Ich habe diese Ausnahme bekommen:

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

Also wechselte ich zu:

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

wo "id" ist

id serial not null primary key

Und das Problem ist gelöst. Also nahm ich das an 

prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);

ist hier nicht richtig. Die offizielle Anleitung ist here , Kapitel 13.2.8: Automatisch generierte Schlüssel abrufen

10
xKommando

Eine Lösung, die NamedParameterJdbcTemplate mit Sequence.nextval verwendet: 

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

Diese Lösung gefällt mir, da sie mit NamedParameterJdbcTemplate verwendet wird, da die Parameter nach Namen übergeben werden und der Code besser lesbar und weniger fehleranfällig ist, insbesondere wenn große Abfragen vorhanden sind.

5
Vasile Bors

Es gibt offenbar einige bekannte Probleme mit Keyholder und PostgreSQL. Schauen Sie sich den Workaround unter diesem Link an Spring JDBC - Zuletzt eingefügte ID

Überprüfen Sie auch die Datenbanktabelle direkt, um festzustellen, ob der Datensatz ordnungsgemäß eingefügt wurde (d. H. Mit PK). Dies hilft, das Problem einzugrenzen.

1
Kshitij

Schauen Sie sich diesen Beitrag an, insbesondere die akzeptierte Antwort der Verwendung der INSERT ... RETURNING-Syntax:

Wie bekomme ich einen Wert aus der letzten eingefügten Zeile?

Dies ist der beste Weg, um diesen Wert in PostgreSQL zu erhalten, da Sie nur eine Netzwerkrundfahrt durchführen und dies als eine einzige atomare Operation auf dem Server durchführen.

1
Matthew Wood

Ich hatte das gleiche Problem und es stellte sich heraus, dass meine Tabellen-ID nicht automatisch inkrementiert wurde.

1
Eidan Spiegel

Ich stand vor einem ähnlichen Problem. Ich weiß nicht, warum ich genau dieses Problem hatte, aber es ist gut, dass ich dies mithilfe des folgenden Codes beheben kann:

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

Hoffe das hilft jemandem.

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

Vergessen Sie nicht, die Namen für die automatisch generierten Spalten festzulegen.

0
N. Osil