Le traitement d'un ResultSet SQL comme un Scala Flux
Quand j'ai une requête à une base de données et de recevoir une (avant uniquement en lecture seule) jeu de résultats, le jeu de résultats agit comme une liste de lignes de la base de données.
Je suis en train d'essayer de trouver un moyen de traiter ce ResultSet comme un Scala Stream
. Cela permettra à des opérations telles que le filter
, map
, etc., alors que ne pas consommer de grandes quantités de RAM.
J'ai mis en place une queue-méthode récursive pour extraire les éléments individuels, mais cela nécessite que tous les éléments soient en mémoire dans le même temps, un problème si le jeu de résultats est très large:
//Iterate through the result set and gather all of the String values into a list
//then return that list
@tailrec
def loop(resultSet: ResultSet,
accumulator: List[String] = List()): List[String] = {
if (!resultSet.next) accumulator.reverse
else {
val value = resultSet.getString(1)
loop(resultSet, value +: accumulator)
}
}
- Pourriez-vous utiliser un objet iterable au lieu d'un Ruisseau pour faire ce que vous voulez?
- Également un flux de retenir la valeur dans la mémoire de toute façon si vous ne économiser de la mémoire au moment où vous atteignez la fin de la liste.
- Je pense que sans jdbc drapeau/option qui rend jdbc lui-même flux, les résultats, vous avez toujours une copie complète des données dans la mémoire, construit par votre api jdbc.
Vous devez vous connecter pour publier un commentaire.
Je n'ai pas tester, mais pourquoi ne serait-il pas de travail?
Stream
. Je peux appliquermap
,filter
, etc. directement à elle.Iterator
est quehasNext
est côté-effet-gratuit. Il pourrait être appelé à n'importe quel nombre de fois entre deux appels ànext
. Est-il quelque chose empêcher que cela devient un problème?mysql-connector-java
version 6. Vous ne savez pas si j'ai fait quelque chose de mal, mais monResultSet
est fermé sur la deuxièmenext()
appel, afin que je puisse récupérer uniquement une ligne de résultat. La seule façon c'est pas de l'auto-fermé avant j'ai eu toutes les lignes semble être l'utilisation d'while (rs.next()) {...}
, j'ai donc ajouter des éléments individuellement à unscala.collection.mutable.ListBuffer
dans lewhile
. Ne semble pas assez, mais ne pouvait pas trouver une autre façon.new Iterator[String]{ ... }.toList
au lieu de.toStream
va chercher l'ensemble des résultats immédiatement, au lieu de simplement la première ligne.Fonction d'utilité pour @elbowich réponse:
Vous permet d'utiliser l'inférence de type. E. g.:
Cela sonne comme une formidable opportunité pour un implicite de la classe. Tout d'abord, définir l'implicite de la classe quelque part:
Ensuite, il suffit d'importer l'implicite de la classe partout où vous avez exécuté votre requête et défini l'objet ResultSet:
Enfin obtenir les données à l'aide de la toStream méthode. Par exemple, obtenir tous les id comme indiqué ci-dessous:
j'ai besoin de quelque chose de similaire. Bâtiment sur elbowich est très cool réponse, j'ai emballé un peu, et au lieu de la chaîne, j'ai retourner le résultat (de sorte que vous pouvez obtenir n'importe quelle colonne)
J'avais besoin d'accéder à des métadonnées de la table, mais cela fonctionne pour les lignes de la table (on pourrait faire un stmt.executeQuery(sql) au lieu de md.getColumns):
Iterator[ResultSet]
, et de la baisse de latoStream
)Parce que ResultSet est juste un objet mutable être navigué par ensuite, nous devons définir notre propre concept de la ligne suivante. Nous pouvons le faire avec une fonction d'entrée comme suit:
EDIT:
Traduire de diffuser ou de quelque chose d'autre que ci-dessus.
Cette mise en œuvre, bien que plus long et plus encombrant il est dans une meilleure correspondance avec le jeu de résultats du contrat. L'effet secondaire n'a été supprimé depuis hasNext(...) et a déménagé dans next().
Je pense que la plupart des au-dessus des implémentations a un non déterministe
hasNext
méthode. De l'appeler deux fois permet de déplacer le curseur à la deuxième ligne. Je vous conseille d'utiliser quelque chose comme ça: