2011-07-01 336 views
10

我的目標實際上是將數據庫的所有數據轉儲到XML文件中。數據庫不是非常大,大約300MB。問題是我的內存限制只有256MB(在JVM中)。很顯然,我不能只是把所有的東西都看成記憶。在MyBatis中處理大量數據

我設法解決這個問題,使用iBatis(是的,我的意思是iBatis,而不是myBatis)通過多次調用它的getList(... int skip, int max),增加skip。這確實解決了我的記憶問題,但我對速度並沒有留下深刻的印象。變量名稱暗示了該方法在引擎蓋下執行的操作是讀取整個結果集,然後跳過指定的記錄。這聽起來對我來說是相當多餘的(我不是說這就是這個方法所做的,我只是基於變量名猜測)。

現在,我切換到我的應用程序的下一個版本myBatis 3。我的問題是:有沒有更好的方法來處理myBatis中塊的大量數據塊?有沒有辦法讓myBatis進程開始N個記錄,並將它們返回給調用者,同時保持結果集連接處於打開狀態,以便下次用戶調用getList(...)時,它將從N + 1記錄開始讀取,而不執行任何操作「退出」?

回答

7

不,mybatis沒有完整的流式結果能力還有

編輯1: 如果不需要嵌套的結果映射,那麼你可以實現一個自定義的結果處理程序流的結果。在當前發佈的MyBatis版本上。 (3.1.1)當前的限制是當你需要做複雜的結果映射。 NestedResultSetHandler不允許自定義結果處理程序。修復程序是可用的,它看起來目前是3.2的目標。見Issue 577

總之,要使用MyBatis流式傳輸大型結果集,您需要。

  1. Implement your own ResultSetHandler
  2. 增加獲取大小。 (如下面由Guillaume Perrot所述)
  3. 對於嵌套結果映射,請使用Issue 577上討論的修復。此修補程序還解決了一些大型結果集的內存問題。
16

myBatis CAN流結果。你需要的是一個自定義的結果處理程序。有了這個,你可以分別取出每一行並將其寫入你的XML文件。整體方案如下所示:

session.select(
    "mappedStatementThatFindsYourObjects", 
    parametersForStatement, 
    resultHandler); 

其中resultHandler是實現ResultHandler接口的類的實例。該界面只有一個方法handleResult。此方法爲您提供了一個ResultContext對象。從這個上下文中,您可以檢索當前正在閱讀的行並對其執行操作。

handleResult(ResultContext context) { 
    Object result = context.getResultObject(); 
    doSomething(result); 
} 
+8

您的回答缺少一個重要的細節:您需要在您的語句中添加@Options(fetchSize = Integer.MIN_VALUE)(或XML等效項)。而且它在MyBatis 3.0.5中不起作用(我使用Eclipse Memory Analyzer進行了檢查)。我升級到MyBatis 3.1.1,現在流媒體正常工作。 –

2

handleResult接收儘可能多的記錄,查詢得到,沒有暫停。

當有太多記錄要處理時,我使用了sqlSessionFactory.getSession()。getConnection()。 然後,像普通的JDBC一樣,獲取一個Statement,獲取Resultset,並逐個處理記錄。不要忘記關閉會議。

0

如果只是從表中轉儲沒有任何排序要求的所有數據,爲什麼不直接在SQL中進行分頁?爲查詢語句設置一個限制,其中指定不同的記錄ID作爲偏移量,將整個表分成塊,如果行限制是合理的數字,則可以將每個塊直接讀入內存。

的SQL可能是這樣的:

SELECT * FROM resource 
    WHERE "ID" >= continuation_id LIMIT 300; 

我認爲這可以被看作是一種替代解決方案,爲您傾倒的塊中的所有數據,在MyBatis的擺脫的不同功能的問題,或任何持久層,支持。