我遇到的问题是我的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);
}
}
如果在循环中调用此方法,它在某些时候总是会耗尽临时表空间。
释放空间的唯一可靠方法是关闭连接并打开一个新连接(例如使用clob.getInternalConnection.close()
),但这会降低应用程序的速度并使当前的多线程方法无法使用。 / p>
可悲的是,关于ojdbc的oracle文档并没有真正有用,谷歌只发现文章告诉我使用lobs的free()
方法,甚至没有用oracles临时clobs实现。
附加说明:
使用oracles APEXExport.class
导出大型工作区时也会出现此问题。
驱动程序和系统细节:
如果你有APEX-Application,请测试代码:
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();
更新
经过更多测试后,我发现clobs在某些时候被释放而没有关闭连接。所以看起来free()
实际上是lazyFree()
。但这可能需要一分多钟
我也可以将CLOB转换为Clob,不知道我之前做错了什么。如果使用Clob,问题将保持不变。
答案 0 :(得分: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 = statement.getCLOB)。
现在时间不够,但稍后会编辑详细的代码。如果你能在上面工作,那就好了。