我正在开发一个运行在Tomcat 6上的Java项目,它连接到一个MySQL数据库。所有程序都按照他们的要求运行,无论是在本地测试客户服务器上的测试时。然而,有一个例外,那就是一个检索大量数据来生成报告的过程。存储过程在从MySQL执行时需要13分钟左右的时间。当我在本地运行应用程序并连接到在线数据库时,该过程确实起作用,唯一不起作用的是它在客户端的服务器上运行。Java storedProcedure停止与OutOfMemoryError
客户端对他的服务器非常有保护,所以我们对它的控制有限,但他们确实希望我们解决问题。当我检查日志文件时,从执行存储过程的函数中不会引发错误。并且在代码中放置一些调试日志,它会显示它确实进入了执行调用,但在调用之后不会记录调试,也不会将错误记录到catch中,而是进入finally部分。
他们声称MySQL日志中没有超时错误。
如果任何人有任何想法可能会导致此问题,任何帮助将不胜感激。
更新:
经过一番唠叨服务器管理员,我终于得到了进入卡塔利娜日志,这些日志中,我终于发现,有一些意义的错误:
Exception in thread "Thread-16" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2894)
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:117)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:407)
at java.lang.StringBuffer.append(StringBuffer.java:241)
at be.playlane.mink.database.SelectExportDataProcedure.bufferField(SelectExportDataProcedure.java:68)
at be.playlane.mink.database.SelectExportDataProcedure.extractData(SelectExportDataProcedure.java:54)
at org.springframework.jdbc.core.JdbcTemplate.processResultSet(JdbcTemplate.java:1033)
at org.springframework.jdbc.core.JdbcTemplate.extractReturnedResultSets(JdbcTemplate.java:947)
at org.springframework.jdbc.core.JdbcTemplate$5.doInCallableStatement(JdbcTemplate.java:918)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:876)
at org.springframework.jdbc.core.JdbcTemplate.call(JdbcTemplate.java:908)
at org.springframework.jdbc.object.StoredProcedure.execute(StoredProcedure.java:113)
at be.playlane.mink.database.SelectExportDataProcedure.execute(SelectExportDataProcedure.java:29)
at be.playlane.mink.service.impl.DefaultExportService$ExportDataRunnable.run(DefaultExportService.java:82)
at java.lang.Thread.run(Thread.java:636)
奇怪的是,这不记录到应用程序日志,即使它被包裹在try catch中。现在,基于该错误,问题就出withing这个方法:
public Object extractData(ResultSet rs) throws SQLException, DataAccessException
{
StringBuffer buffer = new StringBuffer();
try
{
// get result set meta data
ResultSetMetaData meta = rs.getMetaData();
int count = meta.getColumnCount();
// get the column names; column indices start from 1
for (int i = 1; i < count + 1; ++i)
{
String name = meta.getColumnName(i);
bufferField(name, i == count, buffer);
}
while (rs.next())
{
// get the column values; column indices start from 1
for (int i = 1; i < count + 1; ++i)
{
String value = rs.getString(i);
bufferField(value, i == count, buffer);
}
}
}
catch (Exception e)
{
logger.error("Failed to extractData SelectExportDataProcedue: ", e);
}
return buffer.toString();
}
private void bufferField(String field, boolean last, StringBuffer buffer)
{
try
{
if (field != null)
{
field = field.replace('\r', ' ');
field = field.replace('\n', ' ');
buffer.append(field);
}
if (last)
{
buffer.append('\n');
}
else
{
buffer.append('\t');
}
}
catch (Exception e)
{
logger.error("Failed to bufferField SelectExportDataProcedue: ", e);
}
}
这些功能的目标是到一定的结果集导出到Excel文件(这发生在一个较高的水平)。
所以,如果任何人有一些优化这个技巧,他们非常欢迎。
哎哟......没有服务器访问权限,你会遇到这个问题。你可以做一个修改后的存储过程的缩短子集:例如:快速运行并通过测试环境运行的TOP 100?或者向应用程序添加一些日志记录,并通过日志进行调试,也许你的应用程序正在吃掉异常。 – 2012-07-27 15:28:15
正如你可以在更新中看到的,我终于掌握了包含有意义错误日志的catalina日志。所以我已经设法找到问题了,但是,我不确定如何优化这个。 – Andy 2012-07-30 08:15:54
你无法理解这一点的原因是它是'错误'而不是'Exception'! (不,添加'catch(Error e)'是**不是**正确的解决方案)另外:你建立一个巨大的'String',这可能是问题的根源,你应该尝试将数据流到任何地方你想要它而不是为它分配一个巨大的对象。 – 2012-07-30 08:18:48