我们在 Java 中的准备好的语句有问题。异常似乎很明显:
Root Exception stack trace:
com.microsoft.sqlserver.jdbc.SQLServerException: The statement must be executed before any results can be obtained.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:170)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.getGeneratedKeys(SQLServerStatement.java:1973)
at org.apache.commons.dbcp.DelegatingStatement.getGeneratedKeys(DelegatingStatement.java:315)
它基本上表明我们正在尝试在执行之前获取查询结果。听起来很有道理。现在,导致此异常的代码如下:
...
preparedStatement.executeUpdate();
ResultSet resultSet = preparedStatement.getGeneratedKeys();
if(resultSet.next()) {
retval = resultSet.getLong(1);
}
...
如您所见,我们在执行语句后获取查询结果。
在这种情况下,我们尝试从刚刚成功执行ResultSet
的查询中获取生成的密钥。INSERT
问题
我们在三个不同的服务器上运行此代码(负载平衡,在 docker 容器中)。奇怪的是,这个异常只发生在第三个 docker 服务器上。其他两个 docker 服务器从来没有遇到过这个异常。
额外:失败的查询每天大约执行 13000 次。(4500 由服务器 3 处理)大多数情况下,查询在服务器 3 上也能正常工作。有时,假设每天 20 次,查询失败。始终相同的查询,始终相同的服务器。从来没有其他服务器之一。
我们尝试过的
- 我们检查了软件版本。但这都是一样的,因为所有服务器都使用相同的 docker 映像运行。
- 我们更新到最新的 Java 微软 SQL 驱动程序
- 我们检查了是否所有的
PreparedStatements
都是使用PreparedStatement.RETURN_GENERATED_KEYS
参数构造的。
看起来这是一些与服务器配置相关的问题,因为 docker 图像都是一样的。但我们找不到原因。有没有人建议问题可能是什么?或者有没有人也遇到过这个问题?