Mam problem, że moja aplikacja Java eksportuje większą liczbę brył z bazy danych, ale zawsze kończy się tymczasowy obszar tabel, ponieważ stare cloby nie są zwalniane.Tymczasowe tabele CLOB nie zostały zwolnione
Uproszczony przykład kod jak zrobić byłoby:
public void getClobAndDoSomething (oracle.jdbc.OracleCallableStatement pLSQLCodeReturningClob) {
try (OracleCallableStatement statement = pLSQLCodeReturningClob) {
statment.registerOutParameter(1, Types.CLOB);
statement.execute();
oracle.sql.CLOB clob = statement.getCLOB(1);
clob.open(CLOB.MODE_READONLY);
Reader reader = clob.getCharacterStream();
BufferedReader bufferedReader = new BufferedReader(reader);
doSomethingWithClob(bufferedReader);
bufferedReader.close();
reader.close();
clob.close();
clob.freeTemporary();
} catch (SQLException e) {
if (e.getErrorCode() == 1652) {
//Server ran out of temporary tablespace
} else
handleException(e);
} catch (IOException e) {
handleException(e);
}
}
Jeśli ta metoda jest wywoływana w pętli będzie zawsze kończy się na wyczerpaniu tymczasowego obszaru tabel w pewnym momencie.
Jedynym niezawodnym sposobem na zwolnienie miejsca jest zamknięcie połączenia i otwarcie nowego (na przykład za pomocą clob.getInternalConnection.close()
), ale spowolniłoby to aplikację i uniemożliwiłoby korzystanie z wielowątkowego podejścia.
Niestety dokumentacja Oracle na ojdbc nie jest zbyt pomocna, a google tylko znajdowało artykuły mówiące o tym, żebym używał metody lobs, która nie jest nawet implementowana przez tymczasowe cloby oracles.
Uwaga dodatkowa:
Kwestia ta ma również wystąpić podczas korzystania wyrocznie APEXExport.class
wyeksportować duży obszar roboczy.
kierowcy i systemowe specyfika:
- System operacyjny: Windows 7 x64 Profesjonalne
- Java: 1.8.0_45 64-Bit
- ojdbc: 6 (? Czy istnieją bardziej szczegółowe wersje)
- Database : Oracle Database 11g Enterprise Edition Wydanie 11.2.0.1.0 - Produkcja 64-bitowa
Kod testu, jeśli posiadasz aplikację APEX:
java.sql.Connection con = getConnection();
String gStmtGetAppClob = "begin ? := wwv_flow_utilities.export_application_to_clob(?, ?, ?, ?); end;";
int appId = 100;
while (true) {
OracleCallableStatement exportApplicationToClob = (OracleCallableStatement) con.prepareCall(gStmtGetAppClob);
exportApplicationToClob.setString(3, "Y"); //Public reports
exportApplicationToClob.setString(4, "N"); //Saved reports
exportApplicationToClob.setString(5, "N"); //Interactive report notifications
exportApplicationToClob.setBigDecimal(2, new BigDecimal(appId));
getClobAndDoSomething(exportApplicationToClob);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
con.close();
Aktualizacja:
Po dalszych badaniach okazało się, że to CLOB są coraz uwolniony w pewnym momencie bez zamykania połączenia. Wygląda więc na to, że free()
jest faktycznie lazyFree()
. Ale może to zająć więcej niż minutę.
Mogę również przekonwertować CLOB na Clob, nie wiem, co robiłem źle wcześniej. Problem pozostaje niezmieniony, jeśli używasz Clob.
Nigdy nie miałem żadnego z tych problemów, gdy trzymałem się standardowego API JDBC, nie używając interfejsu ojdbc API. Upewnij się, że wywołanie 'free()' jest również wykonywane w przypadku wyjątku! –
@LukasEder Good Point z 'free()' w bloku catch. Nie wstawiłem tego do przykładu. Niestety nie mogę używać standardowego API JDBC, ponieważ DB zwraca tymczasowy clob. Standardowy JDBC może obsługiwać tylko cloby przechowywane w tabeli. (Przesyłanie lub przekształcanie prowadzi do wyjątku) –
Przykro mi, tęskniłem za tym szczegółem. Być może mógłbyś zaktualizować swoje pytanie ekstraktem z PL/SQL, do którego dzwonisz? Lub jeszcze lepiej, minimalnie powtarzalny przykład byłby świetny, zbyt. –