You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle ADF中Java调用Oracle SQL连续查同表时随机无数据求助

问题分析与解决方案

针对你在Oracle ADF环境中遇到的同一val1调用getValue方法时而返回price、时而返回null的问题,结合代码和场景,整理以下排查方向和解决方案:

可能的根因

  1. 连接池事务上下文冲突:传入的Connection来自ADF连接池,可能关联了未提交的事务。当其他线程通过同一连接执行了修改table1中val1=1记录的操作但未提交时,你的查询会读取到未提交的中间状态(比如记录被删除后未回滚/提交),导致返回null;事务提交/回滚后查询又恢复正常。
  2. 资源泄漏导致连接状态异常:原代码手动关闭ResultSet和PreparedStatement的方式存在风险——如果ps.executeQuery()抛出异常,rs会为null,此时finally块中调用rs.close()会触发NullPointerException,未被捕获的异常可能导致连接池中的连接处于异常状态,后续使用该连接的查询会出现不可预期的结果。
  3. 数据并发修改: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 08:00:29