Statement.executeUpdate()返回-1时的含义是什么?

lda*_*dam 26 java sql jdbc sql-server-2008

一个在管理工作室中工作的查询以及executeUpdate相同的executeUpdate返回-1,这在我们可以找到的任何文档中都是未定义的.它应该只返回rowcount或0.这是什么意思?如果重要,驱动程序是JDBC-ODBC桥.

例:

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);
Run Code Online (Sandbox Code Playgroud)

查询有效,因为该行被添加到数据库中,奇怪的是它返回-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)
Run Code Online (Sandbox Code Playgroud)

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

Mar*_*eel 27

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

JDBC 4.1规范的第13.1.2.3节陈述了一些内容(很难解释为btw):

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

鉴于这些信息,我想executeUpdate()内部会做一个execute(),然后 - 如execute()将返回false- 它将返回值getUpdateCount(),在这种情况下 - 根据JDBC规范 - 将返回-1.

1)Javadoc的事实证明了这一事实进一步证实了这一点Statement.executeUpdate():

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

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

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

只是为了澄清:鉴于Javadoc executeUpdate()的行为可能是错误的,但可以解释一下.

另外,正如我在其他地方评论的那样,-1可能只是表示:可能有些东西被改变了,但我们根本不知道,或者我们无法给出准确数量的变化(例如,因为在这个例子中它是一块T-执行的SQL).


lda*_*dam 8

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

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

  1. 首先检查错误.(1669年)

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

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

    • 受影响的行数的正数(来自INSERT,UPDATE或DELETE),
    • 零表示没有受影响的行,或者语句是DDL,或
    • a -1表示语句成功,但没有可用的更新计数信息(转换为批量更新计数数组中的Statement.SUCCESS_NO_INFO).(1706年)
  4. 以上都不是.最后一次机会......进入上面的解析器,我们知道更多的结果最初是真的.如果我们出现moreResults false,我们点击DONE标记(DONE(FINAL)或DONE(批量生成)),表示批处理总体成功,但没有关于单个语句更新计数的信息.这与上面的最后一种情况类似,只是没有更新计数.那就是:我们有一个成功的结果(返回true),但我们没有关于它的其他信息(updateCount = -1).(1693年)

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

(强调我的)

所以你们最后都是对的.SQL根本无法分辨出受影响的行数,默认为-1.:)


Aar*_*lla 5

我也没有在任何地方看到这一点,但我的直觉是,这意味着IF阻止了整个语句的执行.

尝试使用IF传递的数据库运行该语句.

还要检查是否涉及可能会改变结果的任何触发器.

[编辑]标准说该函数永远不会返回时-1,这不会强制执行此操作.Java没有前置条件和后置条件.JDBC驱动程序可以返回一个随机数,并且无法阻止它.

如果知道发生这种情况的原因很重要,请对不同的数据库运行语句,直到您尝试了所有执行路径(即IF返回的路径false和返回的路径true).

如果它不那么重要,请将其标记为微软工程师的"聪明伎俩",并记住,当您下次想要自己聪明时,您有多喜欢它.

  • SQL Server JDBC驱动程序不是唯一违反JDBC API协定的驱动程序.请参阅[关于MySQL的`Statement.setFetchSize()`的这个问题(http://stackoverflow.com/questions/9949750/mysql-streaming-result-set-and-jooq-fetchlazy) (3认同)
  • 所有JDBC驱动程序都有......"标准的有趣解释". (3认同)

Sac*_*tre 5

对于针对DB2 for z/OS服务器的executeUpdate语句,返回的值取决于正在执行的SQL语句的类型:

对于可以具有更新计数的SQL语句(例如INSERT,UPDATE或DELETE语句),返回的值是受影响的行数.有可能:

正数,如果操作影响了正数行,并且操作不是分段表空间上的批量删除.

0,如果没有行受操作影响.

-1,如果操作是分段表空间上的批量删除.

对于DB2 CALL语句,返回值-1,因为DB2数据库服务器无法确定受影响的行数.对CALL语句的getUpdateCount或getMoreResults的调用也返回-1.对于任何其他SQL语句,返回值-1.