ORA-01000: 超出打开游标的最大数(解决及原因)

本文详细阐述了如何通过调整最大游标数解决Java代码中数据库操作导致的性能瓶颈,并通过实例代码展示了解决方案,旨在提高数据库操作效率。
clip_image001[4]

既然超出最大游标数, 为了第一间让程序恢复正常运行, 当然"脚疼治脚", 先把最大游标数调大:

(1). 以 DBA 登录 PL/SQL

(2). 打开 Command Window(注意不是 SQL Window)

clip_image002[4]

(3). 输入以下命令, 修改 oracle 最大游标数为 1000
1    SQL> alter system set open_cursors=1000 scope=both;

(4). 查看最大游标数是否已修改成功
1    SQL> show parameter open_cursors;

(5). 重启 tomcat(一定要有这一步, 否则修改不生效)

 

经过以上操作, 票据顺利上传上去了, 可是这样治标不治本, 万一以后来个1000张以上的票据要上传, 那不就又得改游标数了; 在代码里肯定是每处理一张票就打开一个游标的, 这样是错误的. 网上找了这个错误代码的相关说明, 在这里发现以下这段话

    这样的错误很容易出现在Java代码中的主要原因是:Java代码在执行conn.createStatement()和 conn.prepareStatement()的时候,实际上都是相当与在数据库中打开了一个cursor。尤其是,如果你的 createStatement和prepareStatement是在一个循环里面的话,就会非常容易出现这个问题。因为游标一直在不停的打开,而且没有关闭。

在代码里看了一下, 果然是这样, 程序通过循环调用封装好的 executeSql 函数, 来对每张票进行 update, 而 executeSql 里每次都调用了 conn.prepareStatement(); 将其移出循环, 再改回原游标数, 再上传票据, 就不再报错了.
    public static void executeSql(Connection conn, String sql, Object[] parValue) throws Exception{
        PreparedStatement ps = null;
        try {
            LOGGER.info(sql);
            ps = conn.prepareStatement(sql);
            if (parValue != null){
                String params = "";
                for (int i = 0; i < parValue.length; i++){
                    if (i != 0){
                        params += ",";
                    }
                    ps.setObject(i+1, parValue[i]);
                    params += parValue[i];
                }
                LOGGER.info(params);
            }
            ps.execute();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new Exception();
        } finally {
            if (ps != null){
                ps.close();
            }
        }
    }

注: 原代码有进行 ps.close(); 的, 但是仍然无效, 是因为 connection 的 autocommit 设为 false 的原因? 还是因为 connection 是从连接池取的原因呢?

有一个问题说明 connection 与 prepareStatement 进行 close 的关系, 但这里只是说明了直接 close connection, 而没有说明直接 close prepareStatement.
### Navicat 中 ORA-01000 错误解决方案 ORA-01000Oracle 数据库中的常见错误之一,表示已超出打开游标最大数目。此问题通常发生在应用程序未正确关闭先前的游标时,或者当系统设置的最大游标数不足以支持当前的工作负载时。 以下是针对该问题的具体分析和解决方法: #### 1. 增加 `OPEN_CURSORS` 参数 Oracle 的初始化参数 `OPEN_CURSORS` 控制了每个会话可以拥有的最大打开游标数。如果默认值过低,则可能导致 ORA-01000 错误。可以通过修改数据库实例的配置文件来调整这一参数[^2]。 ```sql ALTER SYSTEM SET OPEN_CURSORS=300 SCOPE=BOTH; ``` 上述命令将 `OPEN_CURSORS` 设置为 300,并将其保存到内存和磁盘中以便重启后仍然生效。需要注意的是,在更改之前应评估系统的实际需求并测试性能影响。 #### 2. 修改应用逻辑以及时释放资源 许多情况下,ORA-01000 并非由数据库本身引起,而是由于客户端程序未能妥善管理其使用的游标所致。对于通过 Navicat 进行操作的情况,可能的原因包括查询执行完毕后未显式关闭结果集或连接池泄漏等问题[^3]。 为了防止此类情况发生,开发人员应当遵循以下最佳实践: - **确保每次完成数据检索之后都调用了相应的关闭函数**; - 如果正在运行循环语句批量处理记录,请考虑采用绑定变量的方式减少重复创建新对象的可能性; - 定期监控活动会话的状态以及它们所占用的各种资源指标(如临时表空间使用量、锁等待时间等),从而尽早发现问题所在。 #### 3. 使用 PL/SQL 批量处理代替多次单独 SQL 请求 频繁提交小型事务可能会显著增加服务器端开销并消耗更多可用游标配额。因此推荐改写业务流程使其能够一次性传递全部所需输入参数给存储过程内部实现复杂计算功能后再返回最终成果给前端界面展示出来即可满足大部分场景下的效率追求目标同时降低对外部接口依赖程度进而缓解因并发访问过高而导致的压力状况[^4]。 示例代码如下所示: ```plsql CREATE OR REPLACE PROCEDURE bulk_process(p_ids IN SYS.ODCINUMBERLIST) AS BEGIN FORALL i IN INDICES OF p_ids INSERT INTO target_table (id, value) VALUES (p_ids(i), some_function(p_ids(i))); END; / ``` 以上脚本定义了一个接受数组作为参数的自定义子程序,允许用户传入多个 ID 同步更新对应的目标字段而无需反复建立断连动作节省大量网络传输成本同时也减少了中间件层面上额外维护状态信息所带来的负担效果非常明显值得借鉴推广开来用于优化现有架构设计思路当中去探索更加高效合理的解决方案方向上来讲是非常有意义的一次尝试经历分享给大家共同学习进步成长起来吧! ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值