【oracle】【excel导入】ORA-01000: 超出打开游标的最大数

这篇博客主要记录了一个在使用MyBatis进行批量数据插入时遇到的问题,即Oracle数据库中出现'ORA-00604:递归SQL级别1出现错误'和'ORA-01000:超出打开游标的最大数'的错误。作者通过调整代码,将数据分批提交,每次提交99条,成功解决了这个问题。同时,展示了修改后的代码实现,提高了批量插入的效率。

报错信息 

2021-04-13 14:48:06,154 ERROR (ExceptionHandler.java:49) - An error occurred in com.bosssoft.helpPool.controller.backend.CapitalController#readImpFile

org.apache.ibatis.exceptions.PersistenceException:

### Error committing transaction.  Cause: org.apache.ibatis.executor.BatchExecutorException: com.bosssoft.helpPool.mapper.CapitalMapper.saveCapital (batch index #298) failed. 297 prior sub executor(s) completed successfully, but will be rolled back. Cause: java.sql.BatchUpdateException: ORA-00604: 递归 SQL 级别 1 出现错误

ORA-01000: 超出打开游标的最大数

ORA-01000: 超出打开游标的最大数

### Cause: org.apache.ibatis.executor.BatchExecutorException: com.bosssoft.helpPool.mapper.CapitalMapper.saveCapital (batch index #298) failed. 297 prior sub executor(s) completed successfully, but will be rolled back. Cause: java.sql.BatchUpdateException: ORA-00604: 递归 SQL 级别 1 出现错误

ORA-01000: 超出打开游标的最大数

ORA-01000: 超出打开游标的最大数

at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:26) ~[mybatis-3.2.8.jar:3.2.8]

at org.apache.ibatis.session.defaults.DefaultSqlSession.commit(DefaultSqlSession.java:177) ~[mybatis-3.2.8.jar:3.2.8]

at org.apache.ibatis.session.defaults.DefaultSqlSession.commit(DefaultSqlSession.java:169) ~[mybatis-3.2.8.jar:3.2.8]

at com.bosssoft.helpPool.service.impl.CapitalServiceImpl.saveCapital(CapitalServiceImpl.java:174) ~[help-pool-service-impl-0.0.1-SNAPSHOT.jar:?]

at com.bosssoft.helpPool.service.impl.CapitalServiceImpl.impData(CapitalServiceImpl.java:969) ~[help-pool-service-impl-0.0.1-SNAPSHOT.jar:?]

解决:一次提交99条

@Transactional
public void saveCapitalAdmin(Map<String, Integer> map, List<Capital> capitalList, String tableName) {
    //由于框架自身的mybatis在批量新增的时候,每次都要新建一个sqlsession,效率很低,并且它不读mybatis-config,所以
    //这里采用手动获取批处理sqlsession的方式来处理
    SqlSession sqlSession=getBatchSession();
    CapitalMapper capitalMapper1=sqlSession.getMapper(CapitalMapper.class);
    long startTime = System.currentTimeMillis();
    int i = 0;
    for (Capital capital : capitalList) {
        String uuid = NBUtil.createUUID();
        capital.setCapitalId(uuid);
        capital.setOperationTime(new Date());
        capital.setOperationUserId(TokenManager.getUserCode());
        capital.setOperationRelName(TokenManager.getToken().getUserName());
        capital.setIdcard(capital.getIdcard().toUpperCase());
        capital.setName(capital.getName().replaceAll(" ", ""));
        capital.setIsFormula("01");
        // 判断是否含有字母,含有字母只去前后空格
        if (NBUtil.judgeContainsStr(capital.getName())){
             capital.setName(capital.getName().trim());
        }else{
            capital.setName(capital.getName().replaceAll(" ", ""));
        }
        capitalMapper1.saveCapital(capital, tableName);
        //统计年份
        map.put(capital.getGrantYear(), null == map.get(capital.getGrantYear()) ? 1 : map.get(capital.getGrantYear()) + 1);
        ///99 条提交一次
        i++;
        if(i==99){
            sqlSession.commit();
            logger.info("》》》》》》》》》》》》提交99条");
            i=0;
        }
    }
    long endTime = System.currentTimeMillis();
    sqlSession.commit();
    System.out.println("程序运行时间:" + (endTime - startTime) + "ms");
    sqlSession.close();
}

### 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
发出的红包

打赏作者

程序猿hww

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值