【问题标题】:java.sql.SQLException: ORA-01000: maximum open cursors exceededjava.sql.SQLException: ORA-01000: 超出最大打开游标
【发布时间】:2015-03-29 21:55:00
【问题描述】:

我在 ORA-01000 SQL 异常之上得到了这个。

在我的数据库中,有一个包含 1500 条记录的表,我正在尝试插入这些值。在插入另一个表时出现此错误。

java.sql.SQLException: ORA-01000: 超出最大打开游标
在 oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112) 在 oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331) 在 oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:288) 在 oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:743) 在 oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:213) 在 oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:796) 在 oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1031) 在 oracle.jdbc.driver.T4CPreparedStatement.executeMaybeDescribe(T4CPreparedStatement.java:836) 在 oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1124) 在 oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3285) 在 oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3368) 在 com.exceloid.newdb.NewDBInsertion.insertCLocation(NewDBInsertion.java:1239) 在 com.exceloid.dbmigration.CBPartnerImpl.getCLocationData(CBPartnerImpl.java:1198) 在 com.exceloid.serviceimpl.CBPartnerServiceImpl.doProcess(CBPartnerServiceImpl.java:22) 在 com.exceloid.controller.HomeController.cBPartner(HomeController.java:272) 在 com.exceloid.controller.HomeController.welcomePage(HomeController.java:37) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:606) 在 org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219) 在 org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132) 在 org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) 在 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745) 在 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686) 在 org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80) 在 org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925) 在 org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856) 在 org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936) 在 org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:617) 在 org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:723) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) 在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) 在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) 在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) 在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) 在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293) 在 org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861) 在 org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:606) 在 org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) 在 java.lang.Thread.run(Thread.java:745)

这是我的代码:

Connection connection = null;    
PreparedStatement pst = null;     
ResultSet result = null;    

try {      
            connection = newDbConnection(connection);     
            if(connection != null){      
                 for (CLocation cpayment : list) {    

                        cLocationId = cpayment.getcRegionID();    
                        adClient = cpayment.getAdClientID();    
                        adOrg = cpayment.getAdOrgID();    
                        updated = cpayment.getUpdated();     
                        updatedBy = cpayment.getUpdatedBy();    
                        created = cpayment.getCreated();    
                        createdBy = cpayment.getCreatedBy();    
                        isActive = cpayment.isActive();    
                        city = cpayment.getCity();   
                        postal = cpayment.getPostal();    
                        postalAdd = cpayment.getPostalAdd();    
                        cCountryId = cpayment.getcCountryID();    
                        cCityId = cpayment.getcCityID();    
                        address1 = cpayment.getAddress1();    
                        address2 = cpayment.getAddress2();    
                        cRegionId = cpayment.getcRegionID();   
                        regionName = cpayment.getRegionName();   

                        if(isActive == true) {    
                            InsertIsActive = "Y";    
                        } else {   
                            InsertIsActive = "N";    
                        } 

                        if(ad.equals(adClient)){    
                            final String sql = "SELECT * FROM c_location  where c_location_id = '"+cLocationId+"'";    
                            pst = connection.prepareStatement(sql);    
                            result = pst.executeQuery();    
                            boolean exist=result.next();    
                            if(exist){   
                                 System.out.println("already table data exists");    
                                 flag = true;    
                            } else {    
                                 String sql1="INSERT INTO c_location " + "    VALUES ('"+cLocationId+"', '"+client+"', '"+org+"', '"+InsertIsActive+"', '"+created+"', '"+createdBy+"', '"+updated+"', '"+updatedBy+"', '"+address1+"', '"+address2+"', '"+city+"', '"+postal+"', '"+postalAdd+"', '"+cCountryId+"', '"+cRegionId+"', '"+cCityId+"', '"+regionName+"')";   
                                 System.out.println(sql1);    
                                 pst=connection.prepareStatement(sql);    
                                 pst.executeUpdate();   
                                 flag = true;   
                            }    
                        } else {    
                            System.out.println("new db does not match adclient ID");    
                        }    
                 }     
            }     
        } catch (SQLException e) {    
            e.printStackTrace();     
        } finally {     
            if(result != null){     
                try{   
                    result.close();    
                }catch(Exception e){}    
            }    
            if(pst != null){    
                try{    
                    pst.close();    
                }catch(Exception e){}     
            }    
            if(connection != null){   
                try {    
                    connection.close();    
                } catch (SQLException e){}   
            }    
        }   

我已经关闭了所有的连接我仍然面临这个错误。

我已经在我的 oracle db 控制台中执行了这个命令来增加游标的数量。

ALTER SYSTEM SET OPEN_CURSORS=1337 SID='*' SCOPE=BOTH;

但是同样的错误又出现了。

【问题讨论】:

  • 您正在为列表的每个元素创建一个新的PreparedStatement(如果表不存在,实际上是 两个 语句),但您永远不会关闭这些语句或关联的结果集。另外:您使用 PreparedStatement 进行插入完全错误。您应该准备它一次而不连接值,然后将参数传递给已经准备好的语句。你使用它的方式完全违背了PreparedStatement 的目的
  • 您可能还需要考虑批量处理所有插入。
  • 是的,或者应该有一个MERGE 语句而不是一对SELECT+INSERT。或者也许可以使用某种形式的多表插入:INSERT ALL WHEN ... SELECT ... FROM c_location ....

标签: java oracle oracle11g


【解决方案1】:

更改您的 SQL 语句以使用绑定参数,并且 move 不在循环中

final String sql = "SELECT * FROM c_location  where c_location_id = ?";    
pst = connection.prepareStatement(sql);

在循环中设置绑定参数

pst.setString(1, cLocationId);

您应该对 INSERT 语句执行相同的操作。

【讨论】:

    【解决方案2】:

    您只是关闭最后一条 SQL 语句。

    您正在循环所有 CLocation,为每个 CLocation 打开一个 Preparedstatement,而不关闭单个 CLocation。执行后尝试在循环中关闭 Preparedstatement,因为它们每个都在数据库端创建一个新的数据库游标。

    【讨论】:

      【解决方案3】:

      重写您的代码以使用 try-with-resources 构造。

      见:https://blogs.oracle.com/WebLogicServer/entry/using_try_with_resources_with

      也使用绑定变量。它会更短、更安全、更快。

      【讨论】:

      • 虽然这会稍微简化连接变量的 finally 块,但它不能解决结果集和准备好的语句保持打开状态的问题?
      • java.sql.ResultSet 也实现了 AutoCloseable。我认为应该有第二个嵌套的 try-catch 块,您可以在其中打开 ResultSet
      猜你喜欢
      • 2012-08-24
      • 2013-07-29
      相关资源
      最近更新 更多