80 Stimmen

ID in H2-Datenbank automatisch inkrementieren

Gibt es eine Möglichkeit, eine auto_incrementing BIGINT ID für eine Tabelle zu haben. Sie kann wie folgt definiert werden

id bigint auto_increment

aber das hat keine Auswirkungen (es wird nicht automatisch erhöht). Ich möchte alle Felder außer dem ID-Feld einfügen - das ID-Feld sollte vom DBMS bereitgestellt werden. Oder muss ich etwas aufrufen, um den ID-Zähler zu erhöhen?

174voto

Thomas Mueller Punkte 46988

Das funktioniert bei mir. JDBC URL: jdbc:h2:~/temp/test2

drop table test;
create table test(id bigint auto_increment, name varchar(255));
insert into test(name) values('hello');
insert into test(name) values('world');
select * from test; 

Ergebnis:

ID  NAME  
1   hello
2   world

60voto

Basil Bourque Punkte 256611

IDENTITY

Der moderne Ansatz verwendet die IDENTITY für die automatische Erzeugung einer inkrementellen 64-Bit-Long-Integer-Zahl.

Diese in H2 verwendete Ein-Wort-Syntax ist eine abgekürzte Variante von GENERATED … AS IDENTITY definiert in der SQL:2003 Standard. Siehe Zusammenfassung im PDF-Dokument SQL:2003 ist veröffentlicht worden . Andere Datenbanken setzen dies bereits um, wie zum Beispiel Postgres .

CREATE TABLE event_ 
( 
    pkey_ IDENTITY NOT NULL PRIMARY KEY ,  --  `identity` = auto-incrementing long integer.
    name_ VARCHAR NOT NULL ,
    start_ TIMESTAMP WITH TIME ZONE NOT NULL , 
    duration_ VARCHAR NOT NULL
) 
;

Beispiel für die Verwendung. Es ist nicht nötig, einen Wert für unsere pkey Spaltenwert, da er automatisch von H2 generiert wird.

INSERT INTO event_ ( name_ , start_ , stop_ )
VALUES ( ? , ? , ? ) 
;

Und Java.

ZoneId z = ZoneId.of( "America/Montreal" ) ;
OffsetDateTime start = ZonedDateTime.of( 2021 , Month.JANUARY , 23 , 19 , 0 , 0 , 0 , z ).toOffsetDateTime() ; 
Duration duration = Duration.ofHours( 2 ) ;

myPreparedStatement.setString( 1 , "Java User Group" ) ;
myPreparedStatement.setObject( 2 , start ) ;
myPreparedStatement.setString( 3 , duration.toString() ) ; 

Rückgabe generierter Schlüssel

Statement.RETURN_GENERATED_KEYS

Sie können den Wert erfassen, der bei der Ausführung dieses Einfügebefehls erzeugt wird. Dazu sind zwei Schritte erforderlich. Zuerst übergeben Sie das Flag Statement.RETURN_GENERATED_KEYS wenn Sie Ihre vorbereitete Erklärung erhalten.

PreparedStatement pstmt = conn.prepareStatement( sql , Statement.RETURN_GENERATED_KEYS ) ;

Statement::getGeneratedKeys

Der zweite Schritt ist der Aufruf von [Statement::getGeneratedKeys](https://docs.oracle.com/en/java/javase/11/docs/api/java.sql/java/sql/Statement.html#getGeneratedKeys()) nachdem Sie Ihre vorbereitete Erklärung ausgeführt haben. Sie erhalten eine ResultSet deren Zeilen die Bezeichner sind, die für die erstellte(n) Zeile(n) erzeugt wurden.

Beispiel-Applikation

Hier ist eine vollständige Beispielanwendung. Läuft auf Java 14 mit Textblöcke Vorschaufunktion zum Spaß aktiviert. Mit H2 Version 1.4.200.

package work.basil.example;

import org.h2.jdbcx.JdbcDataSource;

import java.sql.*;
import java.time.*;
import java.util.Objects;

public class H2ExampleIdentity
{
    public static void main ( String[] args )
    {
        H2ExampleIdentity app = new H2ExampleIdentity();
        app.doIt();
    }

    private void doIt ( )
    {
        JdbcDataSource dataSource = Objects.requireNonNull( new JdbcDataSource() );  // Implementation of `DataSource` bundled with H2.
        dataSource.setURL( "jdbc:h2:mem:h2_identity_example_db;DB_CLOSE_DELAY=-1" ); // Set `DB_CLOSE_DELAY` to `-1` to keep in-memory database in existence after connection closes.
        dataSource.setUser( "scott" );
        dataSource.setPassword( "tiger" );

        String sql = null;

        try (
                Connection conn = dataSource.getConnection() ;
        )
        {
            sql = """
                  CREATE TABLE event_
                     ( 
                        id_ IDENTITY NOT NULL PRIMARY KEY,  --  `identity` = auto-incrementing integer number.
                        title_ VARCHAR NOT NULL ,
                        start_ TIMESTAMP WITHOUT TIME ZONE NOT NULL ,
                        duration_ VARCHAR NOT NULL
                      )
                  ;
                  """;
            System.out.println( "sql:  \n" + sql );
            try ( Statement stmt = conn.createStatement() ; )
            {
                stmt.execute( sql );
            }

            // Insert row.
            sql = """
                  INSERT INTO event_ ( title_ , start_ , duration_ )
                  VALUES ( ? , ? , ? )
                  ;
                  """;
            try (
                    PreparedStatement pstmt = conn.prepareStatement( sql , Statement.RETURN_GENERATED_KEYS ) ;
            )
            {
                ZoneId z = ZoneId.of( "America/Montreal" );
                ZonedDateTime start = ZonedDateTime.of( 2021 , 1 , 23 , 19 , 0 , 0 , 0 , z );
                Duration duration = Duration.ofHours( 2 );

                pstmt.setString( 1 , "Java User Group" );
                pstmt.setObject( 2 , start.toOffsetDateTime() );
                pstmt.setString( 3 , duration.toString() );

                pstmt.executeUpdate();
                try (
                        ResultSet rs = pstmt.getGeneratedKeys() ;
                )
                {
                    while ( rs.next() )
                    {
                        int id = rs.getInt( 1 );
                        System.out.println( "generated key: " + id );
                    }
                }
            }

            // Query all.
            sql = "SELECT * FROM event_ ;";
            try (
                    Statement stmt = conn.createStatement() ;
                    ResultSet rs = stmt.executeQuery( sql ) ;
            )
            {
                while ( rs.next() )
                {
                    //Retrieve by column name
                    int id = rs.getInt( "id_" );
                    String title = rs.getString( "title_" );
                    OffsetDateTime odt = rs.getObject( "start_" , OffsetDateTime.class );  // Ditto, pass class for type-safety.
                    Instant instant = odt.toInstant();  // If you want to see the moment in UTC.
                    Duration duration = Duration.parse( rs.getString( "duration_" ) );

                    //Display values
                    ZoneId z = ZoneId.of( "America/Montreal" );
                    System.out.println( "id_" + id + " | start_: " + odt + " | duration: " + duration + "  running from: " + odt.atZoneSameInstant( z ) + " to: " + odt.plus( duration ).atZoneSameInstant( z ) );
                }
            }
        }
        catch ( SQLException e )
        {
            e.printStackTrace();
        }
    }
}

Als Nächstes sehen Sie sich die Ergebnisse der Ausführung an.

Instant , OffsetDateTime , & ZonedDateTime

Zum Zeitpunkt dieser Ausführung ist die aktuelle Standardzeitzone meiner JVM America/Los_Angeles . Zum Zeitpunkt des gespeicherten Moments (23. Januar 2021 um 19 Uhr in Québec) ist die Zone America/Los_Angeles hatte einen Versatz von acht Stunden gegenüber der UTC. Daher ist die OffsetDateTime Objekt, das vom H2 JDBC-Treiber zurückgegeben wird, wird auf einen Offset von -08:00 . Dies ist eine Ablenkung wirklich, so dass in der realen Arbeit würde ich sofort umwandeln, dass OffsetDateTime entweder zu einem Instant für UTC oder ZonedDateTime für eine bestimmte Zeitzone, die ich im Sinn hatte. Seien Sie sich darüber im Klaren, dass die Instant , OffsetDateTime y ZonedDateTime Die Objekte würden alle gleichzeitig denselben Moment, denselben Punkt auf der Zeitachse darstellen. Jeder betrachtet denselben Moment durch eine andere Wanduhrzeit. Stellen Sie sich vor, drei Personen in Kalifornien, Québec und Island (mit der Zeitzone UTC und einem Offset von Null) würden sich in einer Telefonkonferenz unterhalten und alle zum gleichen Zeitpunkt auf die Uhr an ihrer jeweiligen Wand schauen.

erzeugter Schlüssel: 1

id_1 | start_: 2021-01-23T16:00-08:00 | duration: PT2H läuft von: 2021-01-23T19:00-05:00[Amerika/Montreal] bis: 2021-01-23T21:00-05:00[America/Montreal]


Übrigens, in der realen Arbeit an einer App-Buchung Zukunft Ernennungen würden wir in Java und in der Datenbank einen anderen Datentyp verwenden.

Wir würden verwendet haben LocalDateTime y ZoneId in Java. In der Datenbank hätten wir einen Datentyp verwendet, der dem SQL-Standardtyp entspricht TIMESTAMP WITHOUT TIME ZONE mit einer zweiten Spalte für den Namen der gewünschten Zeitzone. Wenn wir Werte aus der Datenbank abrufen, um einen Terminkalender zu erstellen, würden wir die Zeitzone auf die gespeicherte Datumszeit anwenden, um eine ZonedDateTime Objekt. Dies würde es uns ermöglichen, Termine für eine bestimmte Uhrzeit zu buchen, unabhängig von Änderungen der Abweichung von der UTC, die von den Politikern in diesem Land vorgenommen werden.

8voto

beloblotskiy Punkte 870

Ganz einfach:

id int auto_increment primary key

H2 erstellt automatisch ein Sequence-Objekt

6voto

ericj Punkte 1937

Sie können auch Folgendes verwenden default :

create table if not exists my(id int auto_increment primary key,s text);
insert into my values(default,'foo');

-7voto

eveo Punkte 2707
id bigint(size) zerofill not null auto_increment,

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X