2009-09-17 5 views
6

Używamy Spring SimpleJdbcCall do wywoływania procedur składowanych w Oracle, które zwracają kursory. Wygląda na to, że SimpleJdbcCall nie zamyka kursorów i po pewnym czasie przekroczone są max otwarte kursory.ORA-01000: maksymalna liczba otwartych kursorów przekroczyła przy użyciu Spring SimpleJDBCCall

ORA-01000: maximum open cursors exceeded ; nested exception is java.sql.SQLException: ORA-01000: maximum open cursors exceeded spring 

Jest kilka osób na forach, które doświadczyły tego, ale na pozór nie znalazły odpowiedzi. Wygląda na to, że jestem błędem na wiosnę/oracle support.

Ten błąd jest krytyczny i może mieć wpływ na nasze przyszłe wykorzystanie Spring JDBC.

Czy ktoś napotkał poprawkę - czy śledził problem z kodem źródłowym, czy znalazł obejście, które pozwala uniknąć problemu?

Używamy Spring 2.5.6.

Oto nowa wersja kodu przy użyciu SimpleJdbcCall który wydaje się nie być prawidłowo zamykając wynik ustawić, że powraca proc pośrednictwem kursora:

... 
SimpleJdbcCall call = new SimpleJdbcCall(dataSource); 

Map params = new HashMap(); 
params.put("remote_user", session.getAttribute("cas_username")); 

Map result = call 
    .withSchemaName("urs") 
    .withCatalogName("ursWeb") 
    .withProcedureName("get_roles") 
    .returningResultSet("rolesCur", new au.edu.une.common.util.ParameterizedMapRowMapper()) 
    .execute(params); 
List roles = (List)result.get("rolesCur") 

Im starsza wersja kodu, który nie korzysta z wiosna JDBC nie ma tego problemu:

oracleConnection = dataSource.getConnection(); 
callable = oracleConnection.prepareCall(
     "{ call urs.ursweb.get_roles(?, ?) }" ); 
callable.setString(1, (String)session.getAttribute("cas_username")); 
callable.registerOutParameter (2, oracle.jdbc.OracleTypes.CURSOR); 
callable.execute(); 
ResultSet rset = (ResultSet)callable.getObject(2); 
... do stuff with the result set 
if (rset != null) rset.close(); // Explicitly close the resultset 
if (callable != null) callable.close(); //Close the callable 
if (oracleConnection != null) oracleConnection.close(); //Close the connection 

wydaje się, że wiosną JDBC nie dzwoni rset.close(). Jeśli skomentuję tę linię w starym kodzie, to po testowaniu obciążenia otrzymamy ten sam wyjątek bazy danych.

+3

Proszę napisać kod pokazujący, w jaki sposób używasz SimpleJdbcCall. Jest bardzo mało prawdopodobne, że jest to błąd na wiosnę i bardziej prawdopodobny sposób, w jaki go używasz, szczególnie biorąc pod uwagę niestandardowy sposób, w jaki Oracle obsługuje zestawy wyników. – skaffman

+1

+1 ze skaffmanem. Jeśli nie możesz znaleźć problemu, spróbuj zbudować solidny testowy test wcześniej, aby zgłosić błąd na stronie http://jira.springframework.org/ –

Odpowiedz

7

Po wielu testach naprawiliśmy ten problem. Jest to połączenie tego, w jaki sposób korzystaliśmy ze struktury wiosennej i klienta Oracle oraz Oracle DB.Tworzyliśmy nowe SimpleJDBCCalls, które używały metadanych klienta Oracle JDBC, które były zwracane jako kursory, które nie były zamykane i czyszczone. Uważam, że jest to błąd w wiosennej strukturze JDBC w sposobie wywoływania metadanych, ale nie powoduje zamknięcia kursora. Wiosna powinna skopiować metadane z kursora i zamknąć go poprawnie. Nie przeszkadza mi otwarcie wydania jiry ze sprężyną, ponieważ jeśli użyjesz najlepszej praktyki, błąd nie zostanie wyświetlony.

Poprawianie OPEN_CURSORS lub którykolwiek z pozostałych parametrów jest niewłaściwym rozwiązaniem tego problemu i opóźnia jego pojawianie się.

Pracowaliśmy nad nim/naprawiliśmy go, przenosząc SimpleJDBCCall do pojedynczego DAO, tak więc otwarty jest tylko jeden kursor dla każdego wywoływanego przez nas procesem oracle. Te kursory są otwarte przez cały czas trwania aplikacji - co uważam za błąd. Tak długo, jak OPEN_CURSORS jest większy niż liczba obiektów SimpleJDBCCall, nie będzie kłopotów.

+5

Mam nadzieję, że zgłosiłeś to, jeśli uważasz to za błąd :) –

1

Mogę ci obiecać, że to nie jest Wiosna. Pracowałem nad aplikacją Spring 1.x, która pojawiła się w 2005 roku i od tamtego czasu nie ma żadnego połączenia. (WebLogic 9., JDK 5). Nie zamykasz prawidłowo swoich zasobów.

Czy korzystasz z puli połączeń? Który serwer aplikacji wdrażasz? Która wersja wiosny? Wyrocznia? Jawa? Szczegóły, proszę.

-3

Rozwiązanie nie jest na wiosnę, ale w Oracle: należy ustawić parametr OPEN_CURSORS inicjalizacji do pewnej wartości wyższej niż domyślny 50.

Oracle - przynajmniej jako-of 8i, może to się zmieniło - - będzie ponawiał obiekty JDBC PreparedStatement, chyba że pozostawiono je otwarte. Było to drogie i większość osób kończyło na utrzymaniu stałej puli otwartych wyciągów, które są ponownie przesyłane.

(biorąc okiem na docs 10i, to wyraźnie zauważyć, że kierowca OCI będzie buforować PreparedStatements, więc jestem przy założeniu, że natywny sterownik nadal odtwarza ich za każdym razem)

+2

To jest wyciek zasobów, rozwiązaniem problemu wycieku zasobów jest zatrzymanie wyciek, nie dodawać więcej wody. –

+1

@Andrew - dziękuję za komentowanie wraz ze swoim spadkiem. Jednakże, pracując z Oracle od wczesnych lat dziewięćdziesiątych, jestem gotów odpowiedzieć. Po wyjęciu z pudełka jego konfiguracja nie jest odpowiednia dla złożonej aplikacji. Co więcej, OP używa Springa, który bardzo dobrze oczyszcza się po sobie. Wciąż możliwe jest, że OP napisał gdzieś wyciek zasobów, ale o wiele mniej prawdopodobne, niż gdyby wykonywał wyraźne zarządzanie połączeniami. – kdgregory

+0

Zmieniając wszystkie posty, widzę, że PO opublikował zaakceptowaną odpowiedź dwa miesiące po mojej odpowiedzi, wskazując, że w rzeczywistości był to przeciek zasobów z wiosną. Jednakże, biorąc pod uwagę, że rzekomym przeciekiem była Wiosna próbująca buforować metadane, odniosę się do mojego drugiego akapitu i nadal będę odpowiadać na tę odpowiedź. – kdgregory

-2

Oracle OPEN_CURSORS jest kluczem porządku . Mamy małą aplikację 24x7 działającą na Oracle XE z tylko kilkoma pozornie otwartymi kursorami. Mieliśmy sporadyczne błędy maks. Otwartych kursorów, dopóki nie ustawimy wartości inicjalizacyjnej OPEN_CURSORS na> 300

+4

To wyciek zasobów, rozwiązaniem problemu wycieku zasobów jest zatrzymanie wycieku, a nie dodanie większej ilości wody. –

2

Po prostu zachowaj ostrożność, ustawiając OPEN_CURSORS na wyższe i wyższe wartości, ponieważ są narzuty i może to być po prostu pomoc w zespole nad rzeczywistym problemem/błędem w Twój kod.

nie mam doświadczenia z boku wiosną tego ale pracował nad aplikacją, gdzie mieliśmy wiele problemów z ORA-01000 błędów i stale dostosowując OPEN_CURSORS właśnie sprawiło, że problem znika na chwilę ...

3

Cóż, mam ten problem, gdy czytałem BLOBy. Główną przyczyną było to, że aktualizowałem tabelę, a instrukcja zawierająca klauzulę aktualizacji nie została automatycznie zamknięta. Nasty cursorleak zjada wszystkie darmowe kursory. Po jawnym wywołaniu instrukcji statement.close() błąd znika.

Morał - zawsze zamykaj wszystko, aby zamknąć, nie polegaj na automatycznym zamknięciu po usunięciu Oświadczenia.

Powiązane problemy