在 H2数据库中自动增量 ID

有没有一种方法可以为表提供 auto _  增加 BIGINT ID。 可以这样定义

id bigint auto_increment

但是这没有效果(它不会自动增加)。 我想插入所有字段,但 ID 字段-ID 字段应该由 DBMS 提供。 或者我需要调用什么来增加 ID 计数器?

145550 次浏览
id bigint(size) zerofill not null auto_increment,

它对我很有用。 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;

结果:

ID  NAME
1   hello
2   world

很简单:

id int auto_increment primary key

H2将自动创建序列对象

你也可以使用 default:

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

IDENTITY

现代方法使用 IDENTITY类型,自动生成一个递增的64位长整数。

H2中使用的这种单词语法是 SQL: 2003标准中定义的 GENERATED … AS IDENTITY的缩写变体。请参阅 PDF 文档 SQL: 2003已经发布中的摘要。其他数据库正在实现这一点,比如 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
)
;

示例用法。不需要为我们的 pkey列值传递值,因为它是由 H2自动生成的。

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

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

返回生成的键

Statement.RETURN_GENERATED_KEYS

可以捕获在执行插入命令期间生成的值。需要两个步骤。首先,在获取准备好的语句时传递标志 Statement.RETURN_GENERATED_KEYS

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

Statement::getGeneratedKeys

第二步是在执行准备好的语句之后调用 Statement::getGeneratedKeys。您将得到一个 ResultSet,它的行是为创建的行生成的标识符。

示例应用程序

下面是一个完整的应用程序示例。在 Java14上运行,为了好玩启用了 文本块 预览功能。使用 H2版本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();
}
}
}

接下来,在运行时查看结果。

InstantOffsetDateTime,& ZonedDateTime

在执行此操作时,我的 JVM 的当前默认时区是 America/Los_Angeles。在存储时刻(2021年1月23日下午7点在魁北克) ,区域 America/Los_Angeles有一个偏离协调世界时8小时之后。因此,H2JDBC 驱动程序返回的 OffsetDateTime对象被设置为 -08:00的偏移量。这实际上是一种干扰,因此在实际工作中,我会立即将 OffsetDateTime转换为 UTC 的 Instant或者我心目中特定时区的 ZonedDateTime。要清楚地理解,InstantOffsetDateTimeZonedDateTime对象都代表同一时刻,同一时间线上的同一点。每个人通过不同的挂钟时间观看同一时刻。想象一下,在加利福尼亚、魁北克和冰岛(其区域是世界协调时,零的偏移量)的3个人在电话会议结束时都在谈话,他们每个人都在同一个巧合的时刻抬头看着各自墙上的时钟。

生成键: 1

Id _ 1 | start _: 2021-01-23T16:00-08:00 | time: PT2H something running from: 2021-01-23T19:00-05:00[美国/蒙特利尔] to: 2021-01-23T21:00-05:00[美国/蒙特利尔]


顺便说一下,在预约 未来约会的应用程序的实际工作中,我们会在 Java 和数据库中使用不同的数据类型。

我们会在 Java 中使用 LocalDateTimeZoneId。在数据库中,我们将使用类似于 SQL 标准类型 TIMESTAMP WITHOUT TIME ZONE的数据类型,并使用第二列作为预期时区的名称。当从数据库检索值以构建调度日历时,我们将对存储的日期时间应用时区以获取 ZonedDateTime对象。这将使我们能够预约一天中某个时间的约会,而不必考虑该管辖区的政治家对协调世界时的抵消作出的修改。