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

时间:2012-09-13 06:57:36

标签: java sql sql-server-2008 jdbc

在管理工作室和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);

查询有效,因为该行被添加到数据库中,它很奇怪它返回-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,因为它不返回任何内容,对吗?

5 个答案:

答案 0 :(得分:26)

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

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

  

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

根据这些信息,我猜executeUpdate()内部执行execute(),然后 - execute()将返回false - 它将返回{{1}的值在这种情况下 - 根据JDBC规范 - 将返回getUpdateCount()

事实证明,Statement.executeUpdate()的Javadoc说:

  

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

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

  

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

只是澄清一下:鉴于-1的Javadoc行为可能是错误的,但可以解释。

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

答案 1 :(得分:7)

4年后,Microsoft has open sourced their JDBC driver on Github。我今天收到了关于这个问题的通知,然后去看看,我相信我找到了罪魁祸首heremssql-jdbc/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java:1713

基本上,如果SQL Server不是一个明确的结果集,它会尝试理解SQL Server发回的内容。根据评论,它是这样的:

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

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

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

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

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

  10.   

(强调我的)

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

答案 2 :(得分:5)

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

尝试使用IF通过的数据库运行语句。

同时检查是否涉及可能改变结果的触发器。

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

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

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

答案 3 :(得分:5)

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

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

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

0,如果没有行受到操作的影响。

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

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

答案 4 :(得分:4)

这并不能解释为什么会这样,但它解释了为什么会发生这种情况。以下字节代码将-1设置为updateCount构造函数中的内部SQLServerStatement标志:

// Method descriptor #401 (Lcom/microsoft/sqlserver/jdbc/SQLServerConnection;II)V
// Stack: 5, Locals: 8
SQLServerStatement(
  com.microsoft.sqlserver.jdbc.SQLServerConnection arg0, int arg1, int arg2) 
throws com.microsoft.sqlserver.jdbc.SQLServerException;

// [...]

34 aload_0 [this]
35 iconst_m1
36 putfield com.microsoft.sqlserver.jdbc.SQLServerStatement.updateCount:int [27]

现在,我不会分析所有可能的控制流,但我只是说这是内部默认的初始化值,它以某种方式泄露给客户端代码。注意,这也可以通过其他方法完成:

// Method descriptor #383 ()V
// Stack: 2, Locals: 1
final void resetForReexecute() 
throws com.microsoft.sqlserver.jdbc.SQLServerException;

// [...]

10 aload_0 [this]
11 iconst_m1
12 putfield com.microsoft.sqlserver.jdbc.SQLServerStatement.updateCount:int [27]

// Method descriptor #383 ()V
// Stack: 3, Locals: 3
final void clearLastResult();
0 aload_0 [this]
1 iconst_m1
2 putfield com.microsoft.sqlserver.jdbc.SQLServerStatement.updateCount:int [27]

换句话说,您可能安全解释-10相同。如果您依赖此结果值,可以保持安全并按以下方式进行检查:

// No rows affected
if (stmt.executeUpdate() <= 0) {
}
// Rows affected
else {
}

更新:在阅读Mark Rotteveel's answer时,我倾向于同意他的观点,假设-1“未知更新计数”的符合JDBC的值<\ n / em>的。即使相关方法的Javadoc没有记录这一点,它也会记录在JDBC specs, chapter 13.1.2.3 Returning Unknown or Multiple Results中。在这种情况下,可以说IF .. INSERT ..语句将具有“未知更新计数”,因为此语句无论如何都不符合SQL标准。