版权声明:本文为博主原创文章,转载请注明源地址。 https://cloud.tencent.com/developer/article/1433806
这两天的工作是将一1000万条数据库记录(10GB)加载到内存中,加载到500多万条记录的时候,就报了OOM(内存不足)。
解决了所有可能造成内存使用不当的外围问题后,再运行还是这个问题,无法加载全部数据。于是只好沉下心仔细研究了之前很少碰的底层访问数据库的代码(这部分代码是第三方的ORM软件通过模板生成的)。
/**
* Load each the elements using a SQL statement specifying a list of fields to be retrieved and dealt by action.
* @param sql the SQL statement for retrieving
* @param argList the arguments to use fill given prepared statement,may be null
* @param fieldList table of the field's associated constants
* @param startRow the start row to be used (first row = 1, last row = -1)//起始行号
* @param numRows the number of rows to be retrieved (all rows = a negative number)//行数
* @param action Action object for do something(not null)
* @return the count dealt by action
* @throws DAOException
*/
public int loadBySqlForAction(String sql, Object[] argList, int[] fieldList,int startRow, int numRows,Action action) throws DAOException{
PreparedStatement ps = null;
Connection connection = null;
try {
//获取数据库连接
connection = this.getConnection();
//创建PreparedStatement
ps = connection.prepareStatement(sql,
1==startRow?ResultSet.TYPE_SCROLL_INSENSITIVE:ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_READ_ONLY);
//填充PrepareStatement中的?占位符
fillPrepareStatement(ps, argList);
//执行PreparedStatement
return this.loadByPreparedStatement(ps, fieldList, startRow, numRows, action);
} catch (DAOException e) {
throw e;
}catch (SQLException e) {
throw new DataAccessException(e);
} finally {
this.getManager().close(ps);
this.freeConnection(connection);
}
}
在创建PreparedStatement
时,resultSetType
参数设置的是TYPE_SCROLL_INSENSITIVE
或TYPE_SCROLL_SENSITIVE
,
这两个参数的共同特点是允许结果集(ResultSet
)的游标可以上下移动。而默认的TYPE_FORWARD_ONLY
参数只允许结果集的游标向下移动。
我加载这么大量的数据到内存过程中,只是顺序读取每一条记录,TYPE_FORWARD_ONLY
就够了,游标用不着前后移动,于是将改为TYPE_FORWARD_ONLY
,重新生成ORM代码,遂加载成功。
ps = connection.prepareStatement(sql,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
如果PreparedStatement
对象初始化时resultSetType
参数设置为TYPE_FORWARD_ONLY
,在从ResultSet
(结果集)中读取记录的时,对于访问过的记录就自动释放了内存。而设置为TYPE_SCROLL_INSENSITIVE
或TYPE_SCROLL_SENSITIVE
时为了保证能游标能向上移动到任意位置,已经访问过的所有都保留在内存中不能释放。所以大量数据加载的时候,就OOM了。