[英]how to create a string in java to hold huge data without calling Arrays.copyOfRange to avoid out of memory error
[英]How to avoid OOM (Out of memory) error when retrieving all records from huge table?
我有一個任務是將一個巨大的表轉換為自定義XML文件。 我將使用Java來完成這項工作。
如果我只是發出“SELECT * FROM customer”,它可能會返回最終導致OOM的大量數據。 我想知道,有沒有一種方法可以在記錄可用后立即處理,並在sql檢索過程中從內存中刪除記錄?
---於2009年7月13日編輯
讓我詳細說明我的問題。 我有1個db服務器和1個應用服務器。 當我在應用程序中發出選擇查詢時,數據將從數據庫服務器傳輸到應用程序服務器。
我相信(如果我錯了,請糾正我)ResultSet需要等到接收到查詢中的所有記錄。 即使我們將獲取大小設置為4,對於1000記錄表,我們仍然最終在應用服務器的堆內存中有1000條記錄,這是正確的嗎? 獲取大小僅影響從/到數據庫服務器的往返次數。
我的問題是,如何在它到達app服務器后立即開始處理該4(或任何數字)記錄,並將其丟棄以釋放應用服務器中的內存?
通過更多信息,我可以得到更有幫助的答案。
如果您使用的是MySQL:
stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);
來自http://www.oracle.com/technology/tech/java/sqlj_jdbc/htdocs/jdbc_faq.html :
java.util.Properties info = new java.util.Properties();
info.put ("user", "scott");
info.put ("password","tiger");
info.put ("defaultRowPrefetch","15");
getConnection ("jdbc:oracle:oci:@",info);
我想你可以使用相同的解決方案, 這一項 。 可滾動的結果集。
如果您使用JDBC,則可以使用帶有游標的ResultSet,您可以一次迭代一條記錄。 您需要確保將XML一次寫入一個文件,而不是使用DOM來構建XML。
我從我的經驗中學到的一條經驗法則是,您永遠不會將數據庫中的所有數據都帶到您的應用程序服務器。 您可以做的一件事是實現一個過程來分頁數據。
您可以帶一頁包含大約1000-5000條記錄的數據,處理它們,然后再次獲取下一頁的數據。
導出整個表的概念。
(專家注意:我知道它的缺點。)
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
public class FullTableExport {
public static String toXML(String s) {
if (s != null) {
StringBuilder b = new StringBuilder(s.length());
for (int i = 0, count = s.length(); i < count; i++) {
char c = s.charAt(i);
switch (c) {
case '<':
b.append("<");
break;
case '>':
b.append(">");
break;
case '\'':
b.append("'");
break;
case '"':
b.append(""");
break;
case '&':
b.append("&");
break;
default:
b.append(c);
}
}
return b.toString();
}
return "";
}
public static void main(String[] args) throws Exception {
String table = "CUSTOMER";
int batch = 100;
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@server:orcl", "user", "pass");
PreparedStatement pstmt = conn.prepareStatement(
"SELECT /*+FIRST_ROWS(" + batch + ") */ * FROM " + table);
ResultSet rs = pstmt.executeQuery();
rs.setFetchSize(batch);
ResultSetMetaData rsm = rs.getMetaData();
File output = new File("result.xml");
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(output), "UTF-8")), false);
out.printf("<?xml version='1.0' encoding='UTF-8'?>%n");
out.printf("<table name='%s'>%n", toXML(table));
int j = 1;
while (rs.next()) {
out.printf("\t<row id='%d'>%n", j++);
for (int i = 1; i <= rsm.getColumnCount(); i++) {
out.printf("\t\t<col name='%s'>%s</col>%n",
toXML(rsm.getColumnName(i)),
toXML(rs.getString(i)));
}
out.printf("\t</row>%n");
}
out.printf("</table>%n", table);
out.flush();
}
}
編輯缺點(感謝@JS):
在哪個階段發生OOM錯誤,它是在數據檢索或處理數據到XML文件?
如果對其進行數據檢索,則分批獲取數據。 首先獲取總行數,按主鍵對選擇進行排序,並將選定的行限制為可咀嚼的大小。
如果它在創建XML文件時,將每個客戶的XML節點發送到System.out.println,請不要將其保存在內存中。 通過commad行啟動程序並將所有輸出重定向到文件;
java MyConverter > results.txt
在循環記錄時,所有內容都保存在文件中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.