『壹』 你好,java 向資料庫添加大量數據時內存溢出 在不改變內存的情況下如何解決 你當時是怎麼解決的
比如想將一個1000W數據的資料庫表,導出到文件;此時,你要麼進行分頁,oracle當然用三層包裝即可,mysql用limit,不過分頁每次都會新的查詢,而且隨著翻頁,會越來越慢,其實我們想拿到一個句柄,然後向下游動,編譯一部分數據(如10000行)將寫文件一次(寫文件細節不多說了,這個是最基本的),需要注意的時候每次buffer的數據,在用outputstream寫入的時候,最好flush一下,將緩沖區清空下;接下來,執行一個沒有where條件的SQL,會不會將內存撐爆?是的,這個問題我們值得去思考下,通過API發現可以對SQL進行一些操作,例如,通過:PreparedStatement statement = connection.prepareStatement(sql),這是默認得到的預編譯,還可以通過設置:PreparedStatement statement = connection.prepareStatement(sql , ResultSet.TYPE_FORWARD_ONLY , ResultSet.CONCUR_READ_ONLY);
來設置游標的方式,以至於游標不是將數據直接cache到本地內存,然後通過設置statement.setFetchSize(200);設置游標每次遍歷的大小;OK,這個其實我用過,oracle用了和沒用沒區別,因為oracle的jdbc API默認就是不會將數據cache到java的內存中的,而mysql里頭設置根本無效,我上面說了一堆廢話,呵呵,我只是想說,java提供的標准API也未必有效,很多時候要看廠商的實現機制,還有這個設置是很多網上說有效的,但是這純屬抄襲;對於oracle上面說了不用關心,他本身就不是cache到內存,所以java內存不會導致什麼問題,如果是mysql,首先必須使用5以上的版本,然後在連接參數上加上useCursorFetch=true這個參數,至於游標大小可以通過連接參數上加上:defaultFetchSize=1000來設置,例如:
jdbc:mysql://xxx.xxx.xxx.xxx:3306/abc?zeroDateTimeBehavior=convertToNull&useCursorFetch=true&defaultFetchSize=1000
上次被這個問題糾結了很久(mysql的數據老導致程序內存膨脹,並行2個直接系統就宕了),還去看了很多源碼才發現奇跡竟然在這里,最後經過mysql文檔的確認,然後進行測試,並行多個,而且數據量都是500W以上的,都不會導致內存膨脹,GC一切正常,這個問題終於完結了。
『貳』 內存溢出的解決方法
內存溢出是指應用系統中存在無法回收的內存或使用的內存過多,最終使得程序運行要用到的內存大於虛擬機能提供的最大內存。
內存中載入的數據量過於龐大,如一次從資料庫取出過多數據;集合類中有對對象的引用,使用完後未清空,使得JVM不能回收;代碼中存在死循環或循環產生過多重復的對象實體;使用的第三方軟體中的BUG;啟動參數內存值設定的過小;
檢查對資料庫查詢中,是否有一次獲得全部數據的查詢。一般來說,如果一次取十萬條記錄到內存,就可能引起內存溢出。這個問題比較隱蔽,在上線前,資料庫中數據較少,不容易出問題,上線後,資料庫中數據多了,一次查詢就有可能引起內存溢出。因此對於資料庫查詢盡量採用分頁的方式查詢。
檢查代碼中是否有死循環或遞歸調用。
『叄』 關於ACCESS資料庫插入或更新數據的溢出問題
原系統在SQLSERVER資料庫下無任何問題,轉換成ACCESS資料庫後,操作其中一個表Client,這個表有3W多條記錄,語句如下:
public DataSet getClient(string SearchStr)
{
try
{
string SqlStr="Select * from Client where ClientName like '%"+SearchStr+"%'";
OleDbDataAdapter OleDbCommand=new OleDbDataAdapter(SqlStr,Conn());
DataSet TempData=new DataSet();
OleDbCommand.Fill(TempData,"Client");
return TempData;
}
catch(Exception ex)
{
throw ex;
}
}