在一个项目期间,我们发现我们正在执行的一些 SQL 语句(但不是全部)在 Java 应用程序中返回的结果与在 Aquadata 或 Toad 等独立 SQL IDE 中运行时返回的结果不同。这使用 DB2 数据库。
我无法显示实际数据(包含 PHI),但我会模拟一个示例,让您了解正在发生的情况:
AquaData 结果(通过其他方式相信是正确/有效的):
Name | ID | Count
--------------|---------------|---------------
Alexander | 12345 | 15
Debra | 23456 | 34
Igor | 54321 | 3
Francesca | 34567 | 108
Java 结果(通过其他方式认为不正确/无效):
Name | ID | Count
--------------|---------------|---------------
Alexander | 12345 | 15
Debra | 23456 | 33
Igor | 54321 | 3
有几点值得注意:
- 其中一个计数(但不是全部)立即不正确(从 34 变为 33)
- 其中一行完全缺失
顾名思义,Count
行的计算方法是根据 COUNT(*)
语句对 SQL 查询中的其他元素进行计数。
但是,当我们深入研究代码时,我们发现通过更改 PreparedStatement
对象的创建方式,可以使 Java 结果与其他结果完全匹配。
旧版本(产生不正确的结果):
try (PreparedStatement p = conn.prepareStatement(query,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)){
新版本(产生正确的结果):
try (PreparedStatement p = conn.prepareStatement(query)) {
这个简单的更改导致 Java 结果集与 AquaData(和其他方法)结果集完全匹配。深入研究 Java 文档,似乎唯一有意义的更改是默认参数中的 TYPE_SCROLL_INSENSITIVE
参数改为 TYPE_FORWARD_ONLY
;默认参数中的 CONCUR_READ_ONLY
参数未更改。
为什么这会对我们的结果产生如此重大的影响?据我们所知,此查询背后的数据在执行此代码之间(或期间)不会发生变化,因此更改滚动类型不应对结果集产生影响。那么,为什么我们会期望这种变化会对我们的结果产生如此重大的影响呢?
<小时/>其他信息:
DB2 平台:Linux/Unix/Windows
DB2 版本*:10050700 2016 年 3 月 22 日 1:56:57 PM s151221
( Db2-LUW v10.5.0.7 )
JDBC 供应商:IBM
JDBC版本:3.69.24
Java 供应商:IBM
Java 版本:IBM 32 位 Windows SDK,Java 技术版,版本 7
* 通过执行 select versionnumber, version_timestamp, versionbuildlevel from sysibm.sysversions order by 2 desc
获取。
最佳答案
TYPE_SCROLL_INSENSITIVE - ...对结果集底层数据的更改不敏感。这意味着应用程序或服务器可以自由地预取数据,而无需考虑数据在应用程序使用数据时是否可能发生变化。
TYPE_FORWARD_ONLY - ...其光标只能向前移动的对象。但是这些行是在使用时检索的。
CONCUR_READ_ONLY - ...您的 ResultSet 对象可能不会更新。意味着锁可以立即释放。
在不敏感的情况下,您最终会得到“脏读”锁定机制,如果表同时被另一个应用程序更新,则可能会产生不同的结果集。
我希望你的“错误”和“正确”案例总是在变化,并且每次都不会出现完全相同的答案。
关于java - 为什么将 ResultSetType 从 TYPE_SCROLL_INSENSITIVE 更改为 TYPE_FORWARD_ONLY 会更改 SQL 查询的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57416153/