java.sql.SQLException: - ORA-01000: превышено максимальное количество открытых курсоров


115

Я получаю исключение SQL ORA-01000. Так что у меня есть несколько вопросов, связанных с этим.

  1. Связано ли максимальное количество открытых курсоров с количеством подключений JDBC, или они также связаны с объектами операторов и наборов результатов, которые мы создали для одного подключения? (Мы используем пул подключений)
  2. Есть ли способ настроить количество объектов инструкции / набора результатов в базе данных (например, соединений)?
  3. Целесообразно ли использовать оператор переменной экземпляра / объект набора результатов вместо объекта локального оператора / набора результатов метода в однопоточной среде?
  4. Вызывает ли эту проблему выполнение подготовленного оператора в цикле? (Конечно, я мог бы использовать sqlBatch) Примечание: pStmt закрывается после завершения цикла.

    { //method try starts  
      String sql = "INSERT into TblName (col1, col2) VALUES(?, ?)";
      pStmt = obj.getConnection().prepareStatement(sql);
      pStmt.setLong(1, subscriberID);
      for (String language : additionalLangs) {
        pStmt.setInt(2, Integer.parseInt(language));
        pStmt.execute();
      }
    } //method/try ends
    
    { //finally starts
       pStmt.close()
    } //finally ends 
  5. Что произойдет, если conn.createStatement () и conn.prepareStatement (sql) будут вызваны несколько раз для одного объекта подключения?

Edit1: 6. Поможет ли использование объекта Weak / Soft reference statement в предотвращении утечки?

Edit2: 1. Есть ли способ найти все отсутствующие "statement.close ()" в моем проекте? Я так понимаю, это не утечка памяти. Но мне нужно найти ссылку на инструкцию (где close () не выполняется), подходящую для сборки мусора? Любой доступный инструмент? Или надо вручную анализировать?

Пожалуйста, помогите мне понять это.

Решение

Найти открытый курсор в Oracle DB для имени пользователя -VELU

Перейдите на машину ORACLE и запустите sqlplus как sysdba.

[oracle@db01 ~]$ sqlplus / as sysdba 

Тогда беги

SELECT   A.VALUE,
    S.USERNAME,
    S.SID,
    S.SERIAL#
  FROM V$SESSTAT A,
    V$STATNAME B,
    V$SESSION S
  WHERE A.STATISTIC# = B.STATISTIC#
    AND S.SID        = A.SID
    AND B.NAME       = 'opened cursors current'
    AND USERNAME     = 'VELU';

Если возможно, прочтите мой ответ, чтобы лучше понять мое решение.


Вы можете опубликовать свой полный код? Было бы интересно посмотреть, где вы закрываете первые скобки, открытые дляfor (String language : additionalLangs) {
Jåcob

@ Канагавелу Сугумар: почему бы не задать 5 разных вопросов в SO?
Jayan

1
Вот ответ, который я нашел очень полезным: stackoverflow.com/a/4507507/501113
chaotic3quilibrium 05

Посмотрите, будет ли полезен ответ: stackoverflow.com/questions/34716456/…
Ману

Чтобы отслеживать открытые курсоры в Oracle, вы также можете взглянуть на SYS.V$OPEN_CURSORпредставление. Это даст вам не только SID, но и текст SQL.
Bass

Ответы:


291

ORA-01000, ошибка максимального количества открытых курсоров, является чрезвычайно распространенной ошибкой при разработке баз данных Oracle. В контексте Java это происходит, когда приложение пытается открыть больше ResultSets, чем настроено курсоров в экземпляре базы данных.

Общие причины:

  1. Ошибка конфигурации

    • В вашем приложении больше потоков, запрашивающих базу данных, чем курсоров в БД. В одном случае количество соединений и пул потоков превышает количество курсоров в базе данных.
    • У вас есть много разработчиков или приложений, подключенных к одному экземпляру БД (который, вероятно, будет включать много схем), и вместе вы используете слишком много подключений.
    • Решение:

  2. Утечка курсора

    • Приложения не закрывают ResultSets (в JDBC) или курсоры (в хранимых процедурах в базе данных)
    • Решение : утечки курсора - это ошибка; увеличение количества курсоров в БД просто отсрочивает неизбежный сбой. Утечки можно найти с помощью статического анализа кода , JDBC или ведения журнала на уровне приложений и мониторинга базы данных .

Задний план

В этом разделе описываются некоторые теории курсоров и способы использования JDBC. Если вам не нужно знать предысторию, вы можете пропустить это и сразу перейти к «Устранению утечек».

Что такое курсор?

Курсор - это ресурс в базе данных, который хранит состояние запроса, в частности позицию, в которой читатель находится в ResultSet. У каждого оператора SELECT есть курсор, а хранимые процедуры PL / SQL могут открывать и использовать столько курсоров, сколько им требуется. Вы можете узнать больше о курсорах на Orafaq .

Экземпляр базы данных обычно обслуживает несколько разных схем , много разных пользователей, каждая с несколькими сеансами . Для этого у него есть фиксированное количество курсоров, доступных для всех схем, пользователей и сеансов. Когда все курсоры открыты (используются) и поступает запрос, требующий нового курсора, запрос завершается ошибкой ORA-010000.

Поиск и установка количества курсоров

Номер обычно настраивается администратором баз данных при установке. Количество используемых курсоров, максимальное количество и конфигурация доступны в функциях администратора в Oracle SQL Developer . Из SQL это можно установить с помощью:

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

Связь JDBC в JVM с курсорами в БД

Приведенные ниже объекты JDBC тесно связаны со следующими концепциями базы данных:

  • JDBC Connection - это клиентское представление сеанса базы данных и обеспечивает транзакции с базой данных . Соединение может иметь только одну открытую транзакцию одновременно (но транзакции могут быть вложенными)
  • JDBC ResultSet поддерживается одним курсором на базе данных. Когда для ResultSet вызывается close (), курсор отпускается.
  • JDBC CallableStatement вызывает хранимую процедуру в базе данных, часто написанную на PL / SQL. Хранимая процедура может создавать ноль или более курсоров и может возвращать курсор в виде набора результатов JDBC.

JDBC является потокобезопасным: вполне нормально передавать различные объекты JDBC между потоками.

Например, вы можете создать соединение в одном потоке; другой поток может использовать это соединение для создания PreparedStatement, а третий поток может обработать набор результатов. Единственное серьезное ограничение заключается в том, что вы не можете одновременно открывать более одного ResultSet на одном PreparedStatement. См. Поддерживает ли база данных Oracle несколько (параллельных) операций на одно соединение?

Обратите внимание, что фиксация базы данных происходит в соединении, и поэтому все DML (INSERT, UPDATE и DELETE) в этом соединении будут фиксироваться вместе. Следовательно, если вы хотите поддерживать несколько транзакций одновременно, у вас должно быть хотя бы одно соединение для каждой параллельной транзакции.

Закрытие объектов JDBC

Типичный пример выполнения ResultSet:

Statement stmt = conn.createStatement();
try {
    ResultSet rs = stmt.executeQuery( "SELECT FULL_NAME FROM EMP" );
    try {
        while ( rs.next() ) {
            System.out.println( "Name: " + rs.getString("FULL_NAME") );
        }
    } finally {
        try { rs.close(); } catch (Exception ignore) { }
    }
} finally {
    try { stmt.close(); } catch (Exception ignore) { }
}

Обратите внимание, как предложение finally игнорирует любое исключение, вызванное close ():

  • Если вы просто закроете ResultSet без try {} catch {}, он может выйти из строя и помешать закрытию оператора
  • Мы хотим, чтобы любое исключение, возникшее в теле попытки, передавалось вызывающему. Если у вас есть цикл, например создание и выполнение операторов, не забудьте закрыть каждый оператор внутри цикла.

В Java 7 Oracle представила интерфейс AutoCloseable, который заменяет большую часть шаблонного кода Java 6 некоторым приятным синтаксическим сахаром.

Хранение объектов JDBC

Объекты JDBC можно безопасно хранить в локальных переменных, экземплярах объекта и членах класса. Как правило, лучше:

  • Используйте экземпляр объекта или члены класса для хранения объектов JDBC, которые повторно используются несколько раз в течение более длительного периода, например Connections и PreparedStatements.
  • Используйте локальные переменные для ResultSets, поскольку они обычно получаются, зацикливаются и затем закрываются в рамках одной функции.

Однако есть одно исключение: если вы используете EJB или контейнер сервлетов / JSP, вы должны следовать строгой модели потоковой передачи:

  • Только сервер приложений создает потоки (с которыми он обрабатывает входящие запросы)
  • Только сервер приложений создает соединения (которые вы получаете из пула соединений)
  • При сохранении значений (состояния) между вызовами нужно быть очень осторожным. Никогда не храните значения в ваших собственных кэшах или статических элементах - это небезопасно для кластеров и других странных условий, а сервер приложений может творить ужасные вещи с вашими данными. Вместо этого используйте компоненты с отслеживанием состояния или базу данных.
  • В частности, никогда не удерживайте объекты JDBC (Connections, ResultSets, PreparedStatements и т. Д.) При различных удаленных вызовах - позвольте серверу приложений управлять этим. Сервер приложений не только предоставляет пул соединений, но и кэширует ваши PreparedStatements.

Устранение утечек

Существует ряд процессов и инструментов, помогающих обнаруживать и устранять утечки JDBC:

  1. Во время разработки - безусловно, лучший подход - выявление ошибок на раннем этапе:

    1. Практика разработки: передовая практика разработки должна уменьшить количество ошибок в вашем программном обеспечении, прежде чем оно покинет рабочий стол разработчика. Конкретные практики включают:

      1. Парное программирование для обучения тех, у кого нет достаточного опыта
      2. Кодовые обзоры, потому что многие глаза лучше, чем один
      3. Модульное тестирование, что означает, что вы можете протестировать любую и всю свою кодовую базу с помощью инструмента тестирования, что упрощает воспроизведение утечек.
      4. Используйте существующие библиотеки для пула соединений, а не создавайте свои собственные
    2. Статический анализ кода: используйте такой инструмент, как отличный Findbugs, для выполнения статического анализа кода. Это обнаруживает многие места, где close () не обрабатывалась правильно. У Findbugs есть плагин для Eclipse, но он также работает автономно для разовых работ, имеет интеграцию с Jenkins CI и другими инструментами сборки.

  2. Во время выполнения:

    1. Удерживаемость и фиксация

      1. Если ResultSet удерживается ResultSet.CLOSE_CURSORS_OVER_COMMIT, то ResultSet закрывается при вызове метода Connection.commit (). Это можно установить с помощью Connection.setHoldability () или с помощью перегруженного метода Connection.createStatement ().
    2. Ведение журнала во время выполнения.

      1. Поместите в код хорошие операторы журнала. Они должны быть четкими и понятными, чтобы заказчик, обслуживающий персонал и товарищи по команде могли понять их без обучения. Они должны быть краткими и включать печать состояния / внутренних значений ключевых переменных и атрибутов, чтобы вы могли отслеживать логику обработки. Хорошее ведение журнала является основополагающим для отладки приложений, особенно тех, которые были развернуты.
      2. Вы можете добавить отладочный драйвер JDBC в свой проект (для отладки - фактически не развертывайте его). Один из примеров (я его не использовал) - log4jdbc . Затем вам нужно провести простой анализ этого файла, чтобы увидеть, какие из выполнений не имеют соответствующего закрытия. Подсчет числа открытых и закрытых должен выявить потенциальную проблему.

        1. Мониторинг базы данных. Наблюдайте за своим запущенным приложением с помощью таких инструментов, как функция SQL Developer 'Monitor SQL' или Quest's TOAD . Мониторинг описан в этой статье . Во время мониторинга вы запрашиваете открытые курсоры (например, из таблицы v $ sesstat) и просматриваете их SQL. Если количество курсоров увеличивается и (что наиболее важно) преобладает один идентичный оператор SQL, вы знаете, что у вас есть утечка с этим SQL. Найдите свой код и просмотрите.

Другие мысли

Можете ли вы использовать WeakReferences для обработки закрывающихся соединений?

Слабые и мягкие ссылки - это способы, позволяющие вам ссылаться на объект таким образом, который позволяет JVM собирать мусор для референта в любое время, которое она сочтет нужным (при условии, что на этот объект нет сильных цепочек ссылок).

Если вы передаете ReferenceQueue в конструкторе мягкой или слабой ссылке, объект помещается в ReferenceQueue, когда объект GC'ed, когда он возникает (если это происходит вообще). При таком подходе вы можете взаимодействовать с финализацией объекта, и вы можете закрыть или финализировать объект в этот момент.

Фантомные ссылки немного страннее; их цель - только контролировать финализацию, но вы никогда не сможете получить ссылку на исходный объект, поэтому будет сложно вызвать для него метод close ().

Однако попытка управления запуском GC редко бывает хорошей идеей (Weak, Soft и PhantomReferences сообщают вам после того , как объект поставлен в очередь для GC). Фактически, если объем памяти в JVM велик (например, -Xmx2000m), вы можете никогда не выполнить сборку мусора для объекта, но все равно столкнетесь с ORA-01000. Если память JVM мала по сравнению с требованиями вашей программы, вы можете обнаружить, что объекты ResultSet и PreparedStatement собираются сразу после создания (до того, как вы сможете их читать), что, скорее всего, приведет к сбою вашей программы.

TL; DR: слабый ссылочный механизм - не лучший способ управлять и закрывать объекты Statement и ResultSet.


3
Если вы создаете операторы в цикле, убедитесь, что он закрыт в цикле, иначе вы закроете только последний оператор.
basiljames

Спасибо, basiljames. Просто отредактировал ответ, чтобы добавить то, что вы сделали.
Эндрю Алкок

@ Эндрю Алкок Большое спасибо! Андрей. Не могли бы вы также ответить на 6-е.
Канагавелу Сугумар

@AndrewAlcock Пожалуйста ... пожалуйста ... пожалуйста ... ответьте также на мой седьмой вопрос. Начиная с нашего проекта, мы очень часто сталкиваемся с ORA-01000 при нагрузочном тестировании. Ваш вклад более ценен для меня. Заранее спасибо !!
Канагавелу Сугумар,

RE: 7 - вы можете попробовать поиск по близости с помощью такого инструмента, как grep. Когда вы узнаете SQL (выберите, вставьте, обновите, удалите), обратите внимание на близость слова close () рядом с оператором. Если расстояние находится дальше, чем ожидалось, это может быть способом выяснить, где он отсутствует. lightboxtechnologies.com/2012/07/27/…
Вс,

28

Я добавляю еще немного понимания.

  1. Курсор предназначен только для объекта утверждения; Это ни набор результатов, ни объект подключения.
  2. Но все же мы должны закрыть набор результатов, чтобы освободить некоторую память оракула. Тем не менее, если вы не закроете набор результатов, он не будет учитываться для КУРСОРОВ.
  3. Объект Closing Statement также автоматически закроет объект набора результатов.
  4. Курсор будет создан для всех операторов SELECT / INSERT / UPDATE / DELETE.
  5. Каждый экземпляр ORACLE DB можно идентифицировать с помощью идентификатора безопасности Oracle; аналогично ORACLE DB может идентифицировать каждое соединение с помощью SID соединения. Оба SID разные.
  6. Итак, сеанс ORACLE - это не что иное, как соединение jdbc (tcp); который представляет собой не что иное, как один SID.
  7. Если мы установим максимальное количество курсоров как 500, то это будет только для одного сеанса / соединения / SID JDBC.
  8. Таким образом, у нас может быть много JDBC-соединений с соответствующим no курсоров (операторов).
  9. После завершения работы JVM все соединения / курсоры будут закрыты, ИЛИ JDBCConnection закрывается. КУРСОРЫ, относящиеся к этому соединению, будут закрыты.

Войдите в систему как sysdba.

В Putty (вход в Oracle):

  [oracle@db01 ~]$ sqlplus / as sysdba

В SqlPlus:

UserName: sys as sysdba

Установите значение session_cached_cursors на 0, чтобы у него не было закрытых курсоров.

 alter session set session_cached_cursors=0
 select * from V$PARAMETER where name='session_cached_cursors'

Выберите существующий набор значений OPEN_CURSORS для каждого соединения в БД

 SELECT max(a.value) as highest_open_cur, p.value as max_open_cur FROM v$sesstat a, v$statname b, v$parameter p WHERE a.statistic# = b.statistic# AND b.name = 'opened cursors current' AND p.name= 'open_cursors'  GROUP BY p.value;

Ниже приведен запрос на поиск списка SID / соединений с открытыми значениями курсора.

 SELECT a.value, s.username, s.sid, s.serial#
 FROM v$sesstat a, v$statname b, v$session s
 WHERE a.statistic# = b.statistic#  AND s.sid=a.sid 
 AND b.name = 'opened cursors current' AND username = 'SCHEMA_NAME_IN_CAPS'

Используйте приведенный ниже запрос, чтобы определить sql в открытых курсорах.

 SELECT oc.sql_text, s.sid 
 FROM v$open_cursor oc, v$session s
 WHERE OC.sid = S.sid
 AND s.sid=1604
 AND OC.USER_NAME ='SCHEMA_NAME_IN_CAPS'

Теперь отлаживайте код и наслаждайтесь !!! :)


1
Вот еще один запрос, который, кажется, работает хорошо: stackoverflow.com/a/2560415/32453
rogerdpack

4

Исправьте свой код следующим образом:

try
{ //method try starts  
  String sql = "INSERT into TblName (col1, col2) VALUES(?, ?)";
  pStmt = obj.getConnection().prepareStatement(sql);
  pStmt.setLong(1, subscriberID);
  for (String language : additionalLangs) {
    pStmt.setInt(2, Integer.parseInt(language));
    pStmt.execute();
  }
} //method/try ends
finally
{ //finally starts
   pStmt.close()
} 

Вы уверены, что действительно закрываете свои pStatements, соединения и результаты?

Для анализа открытых объектов вы можете внедрить шаблон делегатора, который обертывает код вокруг ваших объектов состояния, соединения и результатов. Так вы увидите, если объект будет успешно закрыт.

Пример для: pStmt = obj. getConnection () .prepareStatement (sql);

    class obj{ 

    public Connection getConnection(){
    return new ConnectionDelegator(...here create your connection object and put it into ...);

    } 
}


class ConnectionDelegator implements Connection{
    Connection delegates;

    public ConnectionDelegator(Connection con){
       this.delegates = con;
    }

    public Statement prepareStatement(String sql){
        return delegates.prepareStatement(sql);
    }

    public void close(){
        try{
           delegates.close();
        }finally{
           log.debug(delegates.toString() + " was closed");
        }
    }
}

3

Если ваше приложение представляет собой приложение Java EE, работающее на Oracle WebLogic в качестве сервера приложений, возможной причиной этой проблемы является настройка размера кэша инструкций в WebLogic.

Если параметр размера кэша инструкций для конкретного источника данных примерно равен или превышает значение максимального числа открытых курсоров базы данных Oracle, тогда все открытые курсоры могут использоваться кэшированными операторами SQL, которые открыты WebLogic, в результате чего в ошибке ORA-01000.

Чтобы решить эту проблему, уменьшите значение параметра Размер кэша инструкций для каждого источника данных WebLogic, указывающего на базу данных Oracle, чтобы он был значительно меньше, чем максимальное значение числа курсоров в базе данных.

В консоли администратора WebLogic 10 параметр размера кэша операторов для каждого источника данных можно найти в разделе Службы (слева)> Источники данных> (отдельный источник данных)> вкладка Пул соединений.


1
Hibernate также имеет кеш-память. См. Также developer.jboss.org/wiki/…
Пино

3

Я тоже столкнулся с этой проблемой.

java.sql.SQLException: - ORA-01000: maximum open cursors exceeded

Я использовал Spring Framework с Spring JDBC для уровня dao.

Мое приложение каким-то образом пропускало курсоры, и через несколько минут оно выдавало мне это исключение.

После тщательной отладки и анализа я обнаружил, что проблема с индексированием, первичным ключом и уникальными ограничениями в одной из таблиц , используемых в запросе. i.

Мое приложение пыталось обновить ошибочно проиндексированные столбцы . Итак, всякий раз, когда мое приложение получало запрос на обновление индексированных столбцов, база данных пыталась выполнить переиндексацию на основе обновленных значений. Утечки курсоров .

Мне удалось решить проблему, выполнив правильную индексацию столбцов, которые использовались для поиска в запросе, и применив соответствующие ограничения везде, где это необходимо.


2

Сегодня я столкнулся с той же проблемой (ORA-01000). У меня был цикл for в try {} для многократного выполнения оператора SELECT в базе данных Oracle (каждый раз при изменении параметра), а в finally {} у меня был код для закрытия Resultset, PreparedStatement и Connection как обычно , Но как только я достиг определенного количества циклов (1000), я получил ошибку Oracle о слишком большом количестве открытых курсоров.

Основываясь на сообщении Эндрю Алкока выше, я внес изменения так, что внутри цикла я закрыл каждый набор результатов и каждый оператор после получения данных и перед повторным циклом, и это решило проблему.

Кроме того, такая же проблема возникла в другом цикле вставки операторов в другой базе данных Oracle (ORA-01000), на этот раз после 300 операторов. Опять же, это было решено таким же образом, поэтому либо PreparedStatement, либо ResultSet, либо оба они считаются открытыми курсорами, пока они не будут закрыты.


Это не кажется правильным. Spring документирует, что он отвечает за закрытие ResultSets ( docs.spring.io/spring/docs/current/spring-framework-reference/… ).
Райан

просто для пояснения, в этих примерах я не использовал Spring.
Kinnison84

1

Вы установили autocommit = true? Если нет, попробуйте это:

{ //method try starts  
    String sql = "INSERT into TblName (col1, col2) VALUES(?, ?)";
    Connection conn = obj.getConnection()
    pStmt = conn.prepareStatement(sql);

    for (String language : additionalLangs) {
        pStmt.setLong(1, subscriberID);
        pStmt.setInt(2, Integer.parseInt(language));
        pStmt.execute();
        conn.commit();
    }
} //method/try ends { 
    //finally starts
    pStmt.close()
} //finally ends 

Не могли бы вы ответить и на другие вопросы?
Канагавелу Сугумар

2
Autocommit не закрывает соединения - он только автоматически фиксирует каждый оператор сразу после выполнения. Если вы используете автокоммит, вы не получаете значения от одного из самых важных свойств базы данных - транзакций. Вместо этого вы можете рассмотреть возможность использования базы данных NoSQL.
Эндрю Алкок

1

запрос на поиск открытого sql.

SELECT s.machine, oc.user_name, oc.sql_text, count(1) 
FROM v$open_cursor oc, v$session s
WHERE oc.sid = s.sid
and S.USERNAME='XXXX'
GROUP BY user_name, sql_text, machine
HAVING COUNT(1) > 2
ORDER BY count(1) DESC

1

Эта проблема в основном возникает, когда вы используете пул соединений, потому что, когда вы закрываете соединение, это соединение возвращается в пул соединений, и весь курсор, связанный с этим соединением, никогда не закрывается, поскольку соединение с базой данных все еще открыто. Таким образом, одна из альтернатив - уменьшить время простоя соединений в пуле, поэтому, когда соединение простаивает в течение, скажем, 10 секунд, соединение с базой данных будет закрыто, и новое соединение будет создано для помещения в пул.



0

В нашем случае мы использовали Hibernate, и у нас было много переменных, ссылающихся на один и тот же отображаемый объект Hibernate. Мы создавали и сохраняли эти ссылки в цикле. Каждая ссылка открывала курсор и оставалась открытой.

Мы обнаружили это, используя запрос для проверки количества открытых курсоров при запуске нашего кода, переходя через отладчик и выборочно комментируя вещи.

Что касается того, почему каждая новая ссылка открывала другой курсор - рассматриваемый объект имел коллекции других объектов, сопоставленных с ним, и я думаю, что это как-то связано с ним (возможно, не только это само по себе, но в сочетании с тем, как мы настроили режим выборки и настройки кеша). В самом Hibernate были ошибки, связанные с невозможностью закрытия открытые курсоры, хотя, похоже, они были исправлены в более поздних версиях.

Поскольку нам в любом случае не нужно было иметь столько повторяющихся ссылок на одну и ту же сущность, решением было прекратить создавать и удерживать все эти избыточные ссылки. Однажды мы сделали эту проблему, когда отсутствовали.


0

У меня была эта проблема с моим источником данных в WildFly и Tomcat при подключении к Oracle 10g.

Я обнаружил, что при определенных условиях оператор не закрывается даже при вызове statement.close (). Проблема заключалась в используемом нами драйвере Oracle: ojdbc7.jar. Этот драйвер предназначен для Oracle 12c и 11g и, похоже, имеет некоторые проблемы при использовании с Oracle 10g, поэтому я перехожу на ojdbc5.jar, и теперь все работает нормально.


0

Я столкнулся с той же проблемой, потому что запрашивал db более 1000 итераций. Я использовал try и, наконец, в своем коде. Но по-прежнему возникала ошибка.

Чтобы решить эту проблему, я просто зашел в oracle db и выполнил следующий запрос:

ALTER SYSTEM SET open_cursors = 8000 SCOPE = BOTH;

И это сразу решило мою проблему.


Это облегчило некоторые симптомы, но на самом деле не решило проблему. Вам нужно исправить свой код, чтобы он закрыл курсоры после того, как закончил с ними.
APC
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.