Oracle ADF中Java调用Oracle SQL连续查同表时随机无数据求助
问题分析与解决方案
针对你在Oracle ADF环境中遇到的同一val1调用getValue方法时而返回price、时而返回null的问题,结合代码和场景,整理以下排查方向和解决方案:
可能的根因
- 连接池事务上下文冲突:传入的
Connection来自ADF连接池,可能关联了未提交的事务。当其他线程通过同一连接执行了修改table1中val1=1记录的操作但未提交时,你的查询会读取到未提交的中间状态(比如记录被删除后未回滚/提交),导致返回null;事务提交/回滚后查询又恢复正常。 - 资源泄漏导致连接状态异常:原代码手动关闭ResultSet和PreparedStatement的方式存在风险——如果
ps.executeQuery()抛出异常,rs会为null,此时finally块中调用rs.close()会触发NullPointerException,未被捕获的异常可能导致连接池中的连接处于异常状态,后续使用该连接的查询会出现不可预期的结果。 - 数据并发修改:table1中
val1=1的记录被其他进程/线程频繁执行insert/update/delete操作,刚好在查询的间隙发生了数据变更,导致某次查询时记录不存在。
解决方案
1. 修复资源关闭逻辑,避免泄漏
使用Java的try-with-resources语法自动管理资源,确保ResultSet、PreparedStatement无论是否异常都会被正确关闭,避免连接池资源异常:
public String getValue(Connection cn, String val1) throws SQLException { String sql = "select price FROM table1 WHERE val1= ?"; // try-with-resources自动关闭资源 try (PreparedStatement ps = cn.prepareStatement(sql); ResultSet rs = ps.executeQuery()) { ps.setString(1, val1); if (rs.next()) { String price = rs.getString("price"); System.out.println("val1 is in the method --->" + val1 + "\n price " + price); return price; } else { System.out.println("val1 is in the method --->" + val1 + "\n price null"); return null; } } catch (Exception e) { e.printStackTrace(); throw e; } }
2. 排查事务上下文问题
在方法中添加日志,打印当前连接的标识和事务状态,帮助定位是否是连接池的事务冲突:
// 在创建PreparedStatement前添加日志 System.out.println("Connection ID: " + cn.hashCode() + ", val1: " + val1 + ", AutoCommit: " + cn.getAutoCommit());
如果发现出现null时使用的是同一个连接,且该连接的AutoCommit为false,说明该连接关联了未提交的事务。此时可以:
- 如果业务允许,在查询前强制提交事务:
cn.commit(); - 或者从连接池获取独立的查询连接(避免和修改操作共用同一连接)。
3. 验证数据是否真的存在
在查询price前先检查对应val1的记录数,确认是数据不存在还是JDBC查询异常:
// 添加到try-with-resources块之前 try (PreparedStatement countPs = cn.prepareStatement("SELECT COUNT(*) FROM table1 WHERE val1=?")) { countPs.setString(1, val1); ResultSet countRs = countPs.executeQuery(); if (countRs.next()) { System.out.println("val1: " + val1 + ", 记录数: " + countRs.getInt(1)); } }
如果某次返回null时记录数为0,说明确实是数据被修改了;如果记录数为1但查询不到price,说明是JDBC或连接的问题。
4. 确保事务隔离级别正确
Oracle默认隔离级别是读已提交(TRANSACTION_READ_COMMITTED),如果连接的隔离级别被修改为读未提交,可能会读取到未提交的脏数据。可以在方法中显式设置隔离级别:
cn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
内容的提问来源于stack exchange,提问作者YLG
相关产品推荐
相关产品推荐

