当 Statement.executeUpdate() 返回 -1 时是什么意思?

2022-09-01 11:45:28

在管理工作室和 中工作的查询会产生相同的返回 ,这在我们可以找到的任何文档中都是未定义的。它应该只返回行计数或 .这是什么意思?驱动程序是 JDBC-ODBC 桥接器(如果这很重要)。executeUpdateexecuteUpdate-10

例:

String query = "IF NOT EXISTS (SELECT * FROM animals WHERE animal_name ='" + a +"') INSERT INTO " + table + " (animal_name, animal_desc, species_id) VALUES ('" + a + "', '" + b + "', " + c + ")";
int result = statement.executeUpdate(query);
System.out.println(result);

查询工作正常,因为行被添加到数据库中,它返回-1,文档说它只会返回0或rowcount(正如我已经更正的那样)。

更新:

在 Management Studio 中运行此命令会得到“命令已成功完成”。

IF NOT EXISTS (SELECT * FROM animals WHERE animal_name = 'a') 
INSERT INTO animals(animal_name, animal_desc, species_id) VALUES ('a', 'a', 1)

这应该意味着该方法应该返回0,因为它不返回任何内容,对吗?


答案 1

由于执行的语句实际上不是DML(例如,或),而是包含DML的T-SQL片段,我怀疑它不被视为更新查询。UPDATEINSERTEXECUTE

JDBC 4.1 规范的第 13.1.2.3 节陈述了一些内容(顺便说一句,很难解释):

当该方法返回 true 时,将调用该方法来检索 ResultSet 对象。当返回 false 时,该方法返回一个 int。如果此数字大于或等于零,则指示语句返回的更新计数。如果为 -1,则表示没有更多结果。executegetResultSetexecutegetUpdateCount

给定此信息,我猜在内部执行一个 ,然后 - 将返回 - 它将返回 的值,在这种情况下 - 根据JDBC规范 - 将返回 。executeUpdate()execute()execute()falsegetUpdateCount()-1

这进一步证实了以下事实1)Statement.executeUpdate()的Javadoc说:

返回:(1) SQL 数据操作语言 (DML) 语句的行计数或 (2) 不返回任何内容的 SQL 语句的 0

2) 用于 Statement.getUpdateCount() 的 Javadoc 指定:

当前结果作为更新计数;-1(如果当前结果是 ResultSet 对象或没有更多结果)

只是为了澄清:给定Javadoc的行为可能是错误的,但它可以解释。executeUpdate()

另外,正如我在其他地方评论的那样,-1可能只是表明:也许某些内容已更改,但我们根本不知道,或者我们无法给出准确的更改数(例如,因为在此示例中,它是执行的T-SQL的一部分)。


答案 2

因此,4年后,微软在Github上开源了他们的JDBC驱动程序。我今天收到了有关此问题的通知,并去看了一下,我相信我已经找到了这里的罪魁祸首。mssql-jdbc/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java:1713

基本上,如果 SQL Server 不是确定的结果集,则驱动程序会尝试了解它发回的内容。根据评论,它是这样的:

  1. 首先检查错误。(ln 1669)

  2. 不是错误。它是结果集吗?(ln 1680)

  3. 不是错误或结果集。也许是 T-SQL 语句的结果?即,以下之一:

    • 受影响行数的正计数(来自 INSERT、UPDATE 或 DELETE),
    • 零表示没有受影响的行,或者语句是 DDL,或者
    • -1 表示语句成功,但没有可用的更新计数信息(转换为批处理更新计数数组中的Statement.SUCCESS_NO_INFO)。(ln 1706)
  4. 以上都不是。最后的机会在这里...进入上面的解析器,我们知道更多Results最初是真的。如果我们得出更多Results false,则我们命中了DONE令牌(DONE(FINAL)或DONE(RPC在批处理中)),该令牌指示批处理总体上成功,但没有关于单个语句的更新计数的信息。这与上面的最后一种情况类似,只是没有更新计数。也就是说:我们有一个成功的结果(返回 true),但是我们没有关于它的其他信息(updateCount = -1)。(ln 1693)

  5. 到达这里的唯一方法(更多结果仍然是正确的,但没有明显的结果)是TDSParser实际上没有解析任何东西。也就是说,我们在响应中处于EOF。在这种情况下,确实没有更多的结果。我们完成了。(ln 1717)

(强调我的)

所以你们最后是对的。SQL 根本无法判断有多少行受到影响,并且默认为 。:)-1


推荐