gpt4 book ai didi

java - JDBC Prepared Statement 对 session 范围感到困惑

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:23:05 24 4
gpt4 key购买 nike

我在升级 JDBC 驱动程序时遇到问题。我尝试了两种不同的驱动程序JNetDirects JSQLConnect 和 Microsoft 的驱动程序都显示相同的行为。在非自动提交状态下执行多个准备好的语句时,这些语句似乎没有共享 session 状态。这给我带来了麻烦。有没有什么方法可以指示连接语句应该共享相同的 session 状态?

这里是一个如何复制不共享 session 状态的例子。以下片段在 insert.execute(); 行引发异常。标识插入关闭导致的异常表明 session 状态未在两个准备好的语句之间维护。

Connection connection = dataSource.getConnection();
connection.setAutoCommit(false);
PreparedStatement identityON = connection.prepareStatement("SET IDENTITY_INSERT TestStuff ON");
identityON.execute();
identityON.close();

PreparedStatement insert = connection.prepareStatement("INSERT INTO TestStuff (id) VALUES(-1)");
insert.execute(); // Results in Cannot insert explicit value for identity column in table 'TestStuff' when IDENTITY_INSERT is set to OFF.
insert.close();

PreparedStatement identityOFF = connection.prepareStatement("SET IDENTITY_INSERT TestStuff OFF");
identityOFF.execute();
identityOFF.close();

connection.commit();

connection.close();

表创建:

CREATE TABLE TestStuff (
id int identity(1,1) PRIMARY KEY
,col int
)

在排除可能有问题的行为时,我确保 session 状态不会在批处理之间被清除

SET IDENTITY_INSERT TestStuff ON:
GO
INSERT INTO TestStuff (id) VALUES(-1);
GO
SET IDENTITY_INSERT TestStuff OFF:

这将在直接针对 SQL Server 实例执行时起作用。证明批处理不会影响 session 范围。

另一个奇怪的是,@@IDENTITY 将在语句之间进行,但 SCOPE_IDENTITY() 不会。

    PreparedStatement insert = connection.prepareStatement("INSERT INTO TestStuff (Col) VALUES(1)");
insert.execute();
insert.close();

PreparedStatement scoptIdentStatement = connection.prepareStatement("SELECT @@IDENTITY, SCOPE_IDENTITY()");
scoptIdentStatement.execute();
ResultSet scoptIdentRS = scoptIdentStatement.getResultSet();
scoptIdentRS.next();
Short identity = scoptIdentRS.getShort(1);
Short scopeIdent = scoptIdentRS.getShort(2);

PreparedStatement maxIdStatement = connection.prepareStatement("SELECT MAX(id) FROM TestStuff");
maxIdStatement.execute();
ResultSet maxIdRS = maxIdStatement.getResultSet();
maxIdRS.next();
Short actual = maxIdRS.getShort(1);

System.out.println(String.format("Session: %s Scope: %s, Actual: %s", identity, scopeIdent, actual )); // Session: 121 Scope: 0, Actual: 121

SQL Server 中的相同示例和结果:

INSERT INTO TestStuff( col) VALUES (1)
PRINT CONCAT('Session: ', @@IDENTITY, ' Scope: ', SCOPE_IDENTITY() )
-- Session: 122 Scope: 122 (Can't print actual without polluting the output here)

最佳答案

如果您将 PreparedStatement 更改为 Statement for IDENTITY_INSERT 设置,那么这将按您的预期工作

Statement identityON = connection.createStatement();
identityON.execute("SET IDENTITY_INSERT TestStuff ON");
identityON.close();

另请注意 docs :

SCOPE_IDENTITY: Returns the last identity value inserted into an identity column in the same scope. A scope is a module: a stored procedure, trigger, function, or batch. Therefore, if two statements are in the same stored procedure, function, or batch, they are in the same scope.

SCOPE_IDENTITY and @@IDENTITY return the last identity values that are generated in any table in the current session. However, SCOPE_IDENTITY returns values inserted only within the current scope; @@IDENTITY is not limited to a specific scope.

因此来自 Management studio 和 JDBC 驱动程序的值不同。

关于java - JDBC Prepared Statement 对 session 范围感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50282553/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com