为什么从 Java 代码获取时 SQL 服务器序列跳了两个?

Why is SQL Server sequence jumping by two when fetched from Java code?

假设在 SQL 服务器上创建了一个序列:

CREATE SEQUENCE dbo.my_seq
    START WITH 1
    INCREMENT BY 1
    NO CYCLE;
GO

以及以下 Java 代码来获取下一个序列值:

Connection conn = ...;
String sql = "SELECT NEXT VALUE FOR my_seq;";

try (Statement statement = conn.createStatement();
        ResultSet resultSet = statement.executeQuery(sql)) {
    while (resultSet.next()) {
        long seq = resultSet.getLong(1);

        System.out.println(seq);
    }
}

为什么重复执行此代码时序列会跳两个?

2
4
6

我试过打开和关闭 CACHE 选项。没区别。

如果我在 Azure Data Studio 上多次执行相同的查询,序列将递增 1。

我是 运行 Microsoft SQL Server 2019 (RTM-CU15) (KB5008996) - 15.0.4198.2 (X64)。我用 com.microsoft.sqlserver:mssql-jdbc:10.2.0.jre8com.microsoft.sqlserver:mssql-jdbc:11.1.1.jre8-preview 驱动程序尝试了相同的代码并得到了相同的行为。

我分析了 SQL 服务器查询历史,Java 代码每次执行只进行一次查询以获取下一个序列值。

According to Gary's answer 到类似的问题,这是使用 selectMethod=cursor 选项时的已知行为。只需从连接中删除此选项 URL,序列号将不再跳过。

如果出于某种原因必须使用 selectMethod=cursor 怎么办?然后尝试 sys.sp_sequence_get_range 存储过程,如下所示。

Connection conn = ...;
String sequenceName = "my_seq";

try (CallableStatement statement = conn.prepareCall("{call sys.sp_sequence_get_range(?, ?, ?)}")) {
    statement.setString("sequence_name", sequenceName);
    statement.setLong("range_size", 1);
    statement.registerOutParameter("range_first_value", microsoft.sql.Types.SQL_VARIANT);
    statement.execute();

    long seq = statement.getLong("range_first_value");
    
    System.out.println(seq);
}

即使启用了 selectMethod=cursor 选项,它也不会跳过序列号。