JPA 中的最大打开游标超出异常(使用 createNativeQuery 删除记录)

Posted

技术标签:

【中文标题】JPA 中的最大打开游标超出异常(使用 createNativeQuery 删除记录)【英文标题】:Maximum open cursors exceeded exception in JPA (Using createNativeQuery to delete records) 【发布时间】:2018-06-27 11:55:18 【问题描述】:

我收到错误消息(ORA-01000 的发生率高于其他)-

    ORA-01000: 超过打开游标的最大数量 ORA-00604:递归 SQL 级别 1 出错 [ne.jdbc.spi.SqlExceptionHelper] - 没有更多数据可以从套接字读取

我将尝试解释我正在运行的代码场景。

    对 DAO 层的服务调用以删除我通过主节点的记录 从表中查找和删除的键。

    @Transactional(value = "txManagerResult")
    public void deleteCalculatedLkmsEntities(final List<Long> chkdLkmsIds) 
        this.daoResult. deleteCalculatedLkmsEntitiesEnhanced(chkdLkmsIds);
    
    

    DAO 方法从 4 个表中删除记录(有 Parent 和 Child 数据关系,但这种关系不在表上维护 (即没有外键关系)。

    private void deleteCalculatedLkmsEntitiesEnhanced(final List<Long> chkdLkmsIds) 
    
         // Order of the delete is must be maintained as below 
    
         // this will delete  around 100000 rows for 1000 primary key of parent table
         this.deleteEntitiesByPrimaryKeyList("delete from Child_Table_4 where CHKD_PRODUCT_OFFERING_ID in ( "
                       + " select ID from Child_Table_2 where CHKD_LKMS_ID in ( "
                       + "select ID from Parent_Table_1 where id in (:pid) "
                       + ") )"
                       , "pid",
                       chkdLkmsIds);
    
    // this will delete  around 100000 rows for 1000 primary key of parent table
         this.deleteEntitiesByPrimaryKeyList("delete from Child_Table_3 where CHKD_PRODUCT_OFFERING_ID in ( "
                       + " select ID from Child_Table_2 where CHKD_LKMS_ID in ( "
                       + "select ID from Parent_Table_1 where id in (:pid) "
                       + ") )"
                       , "pid",
                       chkdLkmsIds);
    
    // this will delete  around 300000 rows for 1000 primary key of parent table
         this.deleteEntitiesByPrimaryKeyList("delete from Child_Table_2 where CHKD_LKMS_ID in ( "
                       + "select ID from Parent_Table_1 where id in (:pid) )"
                       , "pid",
                       chkdLkmsIds);
    
         // this will delete around 1000 rows
         this.deleteEntitiesByPrimaryKeyList("delete from Parent_Table_1 where ID in (:pid)"
                       , "pid",
                       chkdLkmsIds);
    
     
    private void deleteEntitiesByPrimaryKeyListFromDB(final String query, final String parameter,
                final List<Long> idsToDelete) 
         this.entityManager.createNativeQuery(query)
         .setParameter(parameter, idsToDelete).executeUpdate();
       
    

服务方法由 ForkJoinPool 管理的 4 个并行线程调用。

错误不会在应用程序启动后立即出现,而是在代码执行 10 多个小时后开始出现。以上方法通过线程以循环方式保持运行(删除记录)。此过程运行以完成 900 万条记录的执行。

请帮忙。

【问题讨论】:

您能否也提供您的电话 是否有任何事情提交正在完成的工作 - 从您所展示的内容来看,它看起来不像,除非自动提交已打开? entityManager.createNativeQuery() 是否每次都创建一个新的连接并且没有任何东西关闭它们? @AlexPoole 提交部分由服务级别方法上的注释事务处理。我也怀疑某些东西是打开的,并且没有被 entityManager.createNativeQuery() 关闭,但我找不到,因为这是 JPA 提供的实用程序。 @Hearen : 从 Thread (extend RecursiveAction) 调用服务方法,这些线程由 ForkJoinPool 管理。 4 个并行线程 是否重复使用相同的数据库连接?我认为这可能是问题所在,JDBC 是 AFAIK,不是多线程证明。 【参考方案1】:

查看所有 cmets.. 这可能是由于大量并行调用而发生的。假设 em.createNativeQuery() 正在正确处理数据库资源生命周期。如果您使用的是 oracle DB,则对最大打开游标有限制。您可以在数据库级别增加打开游标的最大数量来解决此问题。

【讨论】:

感谢您的建议,但我认为增加打开游标的最大数量可能是一种解决方法,但困难在于找出需要增加多少允许打开的游标。这并不能保证问题得到解决。 同意..这里的想法是,如果资源达到其容量,我们需要分配更多。您可能需要使用 jmeter 或类似工具对应用程序进行负载测试,并提出基准测试以确定要增加的打开游标的理想数量。但这只有在我们确定我们的应用程序代码没有任何问题之后才应该这样做,例如在这种情况下连接泄漏或资源泄漏。

以上是关于JPA 中的最大打开游标超出异常(使用 createNativeQuery 删除记录)的主要内容,如果未能解决你的问题,请参考以下文章

超出最大游标 SQLException--配置问题或游标泄漏?

jdbc 查询5万条数据出现 ORA-00604: 递归 SQL 级别 1 出现错误 ORA-01000: 超出打开游标的最大数

ora-01000 - 超出最大打开游标错误

java.sql.SQLException: ORA-01000: 超出打开游标的最大数

Doctrine + Oracle = 超出最大打开游标 (ORA-01000)

java.sql.SQLException: ORA-01000: 超出打开游标的最大数