为什么 H2 别名重复插入的行?

Why does H2 alias duplicate inserted rows?

我创建了以下 H2 别名:

CREATE ALIAS INSERT_CHANGE_RECORD AS  '
java.sql.ResultSet insertChangeRecord(final java.sql.Connection conn) throws java.sql.SQLException
{
  String sql = "insert into `change_records` (`made_when`, `made_by`) values (CURRENT_TIMESTAMP(9), ''admin'');";
  java.sql.PreparedStatement ps = conn.prepareStatement(sql, java.sql.Statement.RETURN_GENERATED_KEYS);
  ps.executeUpdate();
  java.sql.ResultSet results = ps.getGeneratedKeys() ;
  return results;
}
';

奇怪的是,当我使用 call INSERT_CHANGE_RECORD(); 调用别名(一次)时,在 table 中创建了 3 条相同的记录,而不是一条。

当我改为使用以下别名定义时(不同之处在于我实际上是从结果集中检索生成的 ID),仅插入 1 行。

CREATE ALIAS IF NOT EXISTS INSERT_CHANGE_RECORD AS  '
Long insertChangeRecord(final java.sql.Connection conn) throws java.sql.SQLException
{
  String sql = "insert into `change_records` (`made_when`, `made_by`) values (CURRENT_TIMESTAMP(9), ''admin'');";
  java.sql.PreparedStatement ps = conn.prepareStatement(sql, java.sql.Statement.RETURN_GENERATED_KEYS);
  ps.executeUpdate();
  java.sql.ResultSet results = ps.getGeneratedKeys();
  results.next();
  return results.getLong(1);
}
';

这是 H2 中的错误,还是对此行为有任何合理的解释?我正在使用 H2 2.1.210.

这是我插入的table的DDL。

CREATE TABLE IF NOT EXISTS `change_records` (
    `id` BIGINT NOT NULL AUTO_INCREMENT CONSTRAINT `change_records_id_pk` PRIMARY KEY,
    `made_when` TIMESTAMP (9) WITH TIME ZONE NOT NULL,
    `made_by` VARCHAR NOT NULL
);

函数别名 returning a ResultSet 被多次调用。您需要检查已通过的连接 URL。如果它等于 jdbc:columnlist:connection,则需要 return 具有正确配置的列的空 ResultSet,您可以使用 org.h2.tools.SimpleResultSet 或其他一些实现。这些调用是在查询实际执行之前的编译或重新编译期间执行的。

String url = conn.getMetaData().getURL();
if (url.equals("jdbc:columnlist:connection")) {
    SimpleResultSet rs = new SimpleResultSet();
    // With some connection options "id" should be used instead
    rs.addColumn("ID", Types.BIGINT, 19, 0);
    return rs;
}
// main code

此结果集的列名称和数据类型必须与您的函数通常 returns 完全相同。注意列名,`id` 通常表示 "ID",但是如果在您的应用程序使用的 JDBC URL 中指定了 ;DATABASE_TO_LOWER=TRUE;DATABASE_TO_UPPER=FALSE,这意味着 "id"。您的函数在此执行期间不应修改任何数据,它只会询问其元数据。

如果URL不同,那是在执行查询或其他命令期间真正的函数调用,您需要执行您的代码。

另见示例: https://github.com/h2database/h2database/blob/45b609dec0e45125e6a93f85c9018d34551332a1/h2/src/test/org/h2/samples/Function.java#L140