Funkcjonalne przetwarzanie kursora bazy danych w Scali
Kiedy muszę odczytać miliony wierszy bazy danych z bazy danych PostgreSQL za pomocą sterownika JDBC, zawsze używam kursora, w przeciwnym razie otrzymam błąd OutOfMemoryError. Oto wzór (pseudokod), którego używam:
begin transaction
execute("declare cursor...")
while (true) {
boolean processedSomeRows = false
resultSet = executeQuery("fetch forward...")
while (resultSet.next()) {
processedSomeRows = true
...
}
if (!processedSomeRows) break
}
close cursor
commit
Jest to bardziej „funkcjonalny” odpowiednik, który wymyśliłem, aby go wdrożyć w Scali:
begin transaction
execute("declare cursor...")
@tailrec
def loop(resultSet: ResultSet,
processed: Boolean): Boolean = {
if (!resultSet.next()) processed
else {
// Process current result set row
loop(resultSet, true)
}
}
while (loop(executeQuery("fetch forward..."), false))
; //Empty loop
close cursor
commit
Wiem, że jest to wymyślone, ale czy istnieje lepszy sposób bez uciekania się do mutacji? Gdybym próbował to zrobić w Haskell, mógłbym wymyślić rozwiązanie, które obejmuje monady, ale nie chcę wysyłać mojego umysłu w dół do tych „krętych, małych fragmentów, wszystkich podobnych”, ponieważ może nigdy nie wrócić…