今天在修改search的建立索引的程序的時候,發現了這個錯誤
使用jdbc讀取SQLServer2005的一個表全部記錄,該表具有10W記錄,結果發生以下錯誤:
com.microsoft.sqlserver.jdbc.SQLServerException: 系統內存不足。請對大型 ResultSet 使用服務器端遊標: Java heap space。ResultSet 大小:236,535,956。JVM 總內存大小:312,213,504。
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(Unknown Source)
at com.microsoft.sqlserver.jdbc.DBComms.receive(Unknown Source)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.doExecuteStatement(Unknown Source)
at com.microsoft.sqlserver.jdbc.SQLServerStatement$StatementExecutionRequest.executeStatement(Unknown Source)
at com.microsoft.sqlserver.jdbc.CancelableRequest.execute(Unknown Source)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeRequest(Unknown Source)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeQuery(Unknown Source)
com.microsoft.sqlserver.jdbc.SQLServerException: 系統內存不足。請對大型 ResultSet 使用服務器端遊標: Java heap space。ResultSet 大小:236,535,956。JVM 總內存大小:312,213,504。
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(Unknown Source)
at com.microsoft.sqlserver.jdbc.DBComms.receive(Unknown Source)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.doExecuteStatement(Unknown Source)
at com.microsoft.sqlserver.jdbc.SQLServerStatement$StatementExecutionRequest.executeStatement(Unknown Source)
at com.microsoft.sqlserver.jdbc.CancelableRequest.execute(Unknown Source)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeRequest(Unknown Source)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeQuery(Unknown Source)
使用以下代碼無效
Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(100);
Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(100);
查文檔得知與sqlserver jdbc驅動的select Method有關。selectMethod分爲direct和cursor。當使用direct時,驅動會一次性載入所有結果集到jvm內存中,因此造成了out of memory;而使用cursor時,會在服務器端創建一個cursor,因此不會佔據客戶端的大量內存,辦法有兩種:
[list=1]
修改SQLServer2005 jdbc的URL: jdbc.url=jdbc:sqlserver://127.0.0.1;instanceName=ProductDB;databaseName=product_index;selectMethod=cursor
這種方式會影響整個應用程序,可能引起其他普通情況的讀取性能下降。使用如下代碼
這種方式會造成SQLServer的API侵入,但不失爲一種更好的辦法。
Statement stmt = con.createStatement(SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);
Statement stmt = con.createStatement(SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);