CLOB的临时表空间未释放

Sim*_*n M 5 java oracle clob ojdbc

我遇到的问题是我的Java应用程序从数据库中导出了大量的clob,但是由于旧的clobs没有被释放,所以总是耗尽临时表空间.

一个简化的代码示例我是如何做到的:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果在循环中调用此方法,它将总是在某个时刻耗尽临时表空间.

释放空间的唯一可靠方法是关闭连接并打开一个新连接(例如通过使用clob.getInternalConnection.close()),但这会降低应用程序的速度并使当前的多线程方法无法使用.

可悲的是,ojdbc上的oracle文档并没有真正有用,谷歌只发现文章告诉我使用free()lobs 的方法甚至没有由oracles临时clobs实现.

附加说明:
使用oracles APEXExport.class导出大型工作区时也会出现此问题.

驱动程序和系统细节:

  • 操作系统:Windows 7 Professional x64
  • Java:1.8.0_45 64位
  • ojdbc:6(有更具体的版本吗?)
  • 数据库:Oracle Database 11g企业版11.2.0.1.0版 - 64位生产

如果您有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();
Run Code Online (Sandbox Code Playgroud)

更新:
经过更多测试后,我发现clobs在某些时候被释放而没有关闭连接.所以看起来它free()实际上是一个lazyFree().但这可能需要一分多钟.
我也可以将CLOB转换为Clob,不知道我之前做错了什么.如果使用Clob,问题将保持不变.

Bra*_*ash 0

在 pl/sql 世界中,这可以通过临时 CLOB 并在循环内重用它来处理。

假设您使用的是java.sql.CLOB.,它似乎没有createTemporary CLOB选项,但oracle.sql.CLOB有。它还具有freeTemporary()清除临时空间的方法。

https://docs.oracle.com/cd/E18283_01/appdev.112/e13995/oracle/sql/CLOB.html

您的调用例程可以创建一个临时 CLOB 并将其作为参数(假设为 p_clob)传递给此方法。每次将查询的返回值赋给p_clob,而不是创建新的CLOB(例如CLOB clob = statements.getCLOB)。

现在时间不够,稍后会编辑详细的代码。如果你可以使用上面的方法,那就太好了。