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.