Implementing Auto-Incrementing IDs in H2 Database: Best Practices

Dec 04, 2025 · Programming · 11 views · 7.8

Keywords: H2 database | auto-incrementing ID | IDENTITY syntax

Abstract: This article explores the implementation of auto-incrementing IDs in H2 database, covering BIGINT AUTO_INCREMENT and IDENTITY syntaxes. It provides complete code examples for table creation, data insertion, and retrieval of generated keys, along with analysis of timestamp data types. Based on high-scoring Stack Overflow answers, it offers practical technical guidance.

In database design, auto-incrementing IDs are essential for ensuring data uniqueness and simplifying insertion operations. H2 database, as a lightweight relational database, offers multiple implementation methods. This article will analyze these approaches in detail and illustrate their applications through code examples.

BIGINT AUTO_INCREMENT Syntax

H2 database supports creating auto-incrementing ID columns using the BIGINT AUTO_INCREMENT syntax. Here is a basic example:

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;

After executing this code, the query results will show IDs auto-incremented to 1 and 2. This approach allows omitting the ID field during data insertion, with the database management system automatically generating it.

IDENTITY Syntax

H2 also supports the IDENTITY type, a simplified syntax based on the SQL:2003 standard. The following example demonstrates table creation with IDENTITY:

CREATE TABLE event_ (
    pkey_ IDENTITY NOT NULL PRIMARY KEY,
    name_ VARCHAR NOT NULL,
    start_ TIMESTAMP WITH TIME ZONE NOT NULL,
    duration_ VARCHAR NOT NULL
);

When inserting data, no value is required for the pkey_ column:

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

Retrieving Generated Keys

In Java applications, the JDBC API can be used to retrieve auto-generated key values. First, specify the Statement.RETURN_GENERATED_KEYS flag when creating a PreparedStatement:

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

After executing the insert operation, call the getGeneratedKeys() method to obtain a ResultSet:

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

Complete Example Application

Below is a full Java example demonstrating the use of H2's IDENTITY type with JDBC:

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());
        dataSource.setURL("jdbc:h2:mem:h2_identity_example_db;DB_CLOSE_DELAY=-1");
        dataSource.setUser("scott");
        dataSource.setPassword("tiger");

        try (Connection conn = dataSource.getConnection()) {
            String sql = """
                CREATE TABLE event_ (
                    id_ IDENTITY NOT NULL PRIMARY KEY,
                    title_ VARCHAR NOT NULL,
                    start_ TIMESTAMP WITHOUT TIME ZONE NOT NULL,
                    duration_ VARCHAR NOT NULL
                );
                """;
            try (Statement stmt = conn.createStatement()) {
                stmt.execute(sql);
            }

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

            sql = "SELECT * FROM event_;";
            try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) {
                while (rs.next()) {
                    int id = rs.getInt("id_");
                    String title = rs.getString("title_");
                    OffsetDateTime odt = rs.getObject("start_", OffsetDateTime.class);
                    Duration duration = Duration.parse(rs.getString("duration_"));
                    System.out.println("id_" + id + " | start_: " + odt + " | duration: " + duration);
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Timestamp Handling Considerations

When working with timestamp data, H2 supports TIMESTAMP WITH TIME ZONE and TIMESTAMP WITHOUT TIME ZONE types. In Java, OffsetDateTime or ZonedDateTime can be used for mapping. For instance, a stored OffsetDateTime object may display different offsets based on the JVM's default time zone but represents the same point in time. In practical applications, appropriate data types should be chosen based on requirements, such as using LocalDateTime with separate time zone storage for handling future appointments.

In summary, H2 database offers flexible and standard-compliant implementations for auto-incrementing IDs. Developers can choose between BIGINT AUTO_INCREMENT or IDENTITY syntax based on project needs and efficiently handle generated keys with the JDBC API.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.