Чанкинг итератора

У мяне ёсць метад, каб атрымаць загрузку аб'ектаў з базы дадзеных, якая вяртае Iterable .

На дадзены момант, я загрузка ResultSet з базы дадзеных, стварэння аб'ектаў з яго і засялення калекцыі з гэтымі аб'ектамі.

Відавочна, я памяці абмежаваны адносна таго, колькі дадзеныя могуць быць загружаны з дапамогай гэтага метаду, і калі я бягу дрэнныя рэчы здараюцца.

Я хацеў бы змяніць рэалізацыю ў дадзеным кавалак з базы дадзеных замест таго, каб атрымліваць усе адразу, а затым выставіць выніковыя аб'екты да кліента праз Iterable інтэрфейсу. Мае драйверы баз дадзеных могуць зрабіць іх няшмат, таму мая першая думка звычай рэалізацыя Iterable , які робіць гэта.

Гэта добры падыход? Яна дзівіць мяне неяк, што можа быць ужо падтрымліваецца падчас выканання або бібліятэк - ня якое ўключае рашэння ORM калі ласка.

2
Ці ёсць прычына, вы хочаце рэалізаваць Iterable і не толькі Итератор ? Пазней, верагодна, будзе прасцей, так як вам не прыйдзецца дадаць магчымасць нанова пачаць ітэрацыі.
дададзена аўтар Joachim Sauer, крыніца
Добрае пытанне - зусім не рацыя
дададзена аўтар brabster, крыніца

2 адказы

Асабіста самае простае рашэнне, якое я магу думаць пра тое, каб рэалізаваць итератора у выглядзе тонкай абалонкі вакол ResultSet . Гэта мае шэраг пераваг:

  • Вам не трэба падаваць прайграваны аператары SQL (вы можаце перадаваць не-адсартаваныя вынікі, напрыклад)
  • Вам не трэба спадзявацца на шматразовае чытанне , які можа быць дарагім
  • Калі ваш драйвер JDBC добра, то вы можаце проста выкарыстоўваць яго вынік струменевай функцыі (папярэджанне: некаторыя драйверы JDBC заўсёды захапіць поўны вынік, як толькі вы пачынаеце ітэрацыю над ёй)
  • Вам не трэба ажыццявіць паўторны запуск у итератора ( Iterable.iterator() можна назваць двойчы, што робіць гэта больш складана).
  • Ці не "запамінанне» раней вернутых дадзеных азначае, што патрабаванні да памяці могуць быць праведзены даволі нізкі

Яна таксама мае некалькі недахопаў:

  • Ваш Итератор рэалізацыя фактычна становіцца экстэрнам рэсурсаў, так як яна звязвае JDBC рэсурс: ён павінен быць «закрытым» ў пэўным сэнсе, што робіць яго цяжэй выкарыстоўваць
  • , калі Итератор вісіць вакол на працягу доўгага часу, то, што <ет> і дазваляе з JDBC Connection тырчэць, якія могуць спатрэбіцца ў іншым месцы ( вы не можаце вярнуць яго ў пул, пакуль Итератор не робіцца).

Альтэрнатыўны спосаб складаецца ў рэалізацыі List (ці Collection ), які лена аднаўляе фракцыі сваіх дадзеных па меры неабходнасці. Гэта можа быць лепш выкарыстоўваць, але даволі шмат складаней пабудаваць (правільна!). Акрамя таго, калі абмежаванні памяці вельмі важныя, то вам неабходна дадаць механізм адкідаць раней адноўленыя аб'екты.

3
дададзена
І альтэрнатыўны спосаб (як вы згадалі) будзе памятаць, зрушэнне, а затым выкарыстоўваць SELECT ... LIMIT M, N «пракручваць» у патрэбнае становішча. Вядома, гэтая інфармацыя можа мяняцца з цягам часу (іншая транзакцыя ўставіла новыя радкі або выдалены), але гэты падыход дазваляе зачыніць JDBC злучэнне дазваляе серверу БД апрацоўваць больш транзакцый у хвіліну.
дададзена аўтар dma_k, крыніца

Я рэалізаваў падыход, прапанаваны Joachim ў адным з маіх прыкладанняў. Я рэалізаваў DestroyableIterator інтэрфейс, які уключаў у сябе Destroy() метад, які ў выпадку ResultSet рэалізацыя абгортка закрываў ResultSet . (Некаторыя бібліятэкі прадастаўляюць гэты інтэрфейс, але я не бачу сэнсу ўвядзення залежнасцяў бібліятэкі дзеля вызначэння інтэрфейсу ў 3 лініі.)

Я таксама злавіў SQLException S і перавёў іх у (незарэгістраваны) Spring DataAccessException s для таго, каб распаўсюдзіць іх праз итератора наступная() і hasNext() метады.

Справа ў дачыненні да трымаючыся рэсурсаў з'яўляецца дапушчальным; Я быў у кантролі кода прыкладання з дапамогай DestroyableIterator і таму былі розныя механізмы тайм-аўту, каб пазбегнуць трымаючыся за жывой ResultSet занадта доўга.

1
дададзена
У Java 7 і вышэй, я прапаную рэалізацыі AutoClosable і выкарыстоўваючы блізка() замест знішчыць() для дадатковага рычажного блока прысмакі.
дададзена аўтар Joachim Sauer, крыніца
Так, гэта тое, што я маю на ўвазе: Няхай DestroyableIterator рэалізацыя AutoClosable (у гэты момант, я б перайменаваць яго ў AutoClosableIterator ;-))
дададзена аўтар Joachim Sauer, крыніца
Толькі тое, што ты тады павінен праверыць AutoCloseable з дапамогай InstanceOf. Магчыма, варта аб'яднання двух інтэрфейсаў як AutoCloseableIterator?
дададзена аўтар Adamski, крыніца