2013-03-05 3 views
7

Ich habe eine große Tabelle, auf die ich gerne über ein Spring Data Repository zugreifen würde.Wie behandelt man eine große Menge von Daten mit Spring Data Repositories?

Derzeit bin ich versucht, die PagingAndSortingRepository Schnittstelle zu erweitern, aber es scheint, dass ich nur Methoden definieren können, die Listen zurückgeben, zB .:

public interface MyRepository extends 
     PagingAndSortingRepository<MyEntity, Integer> 
{ 
    @Query(value="SELECT * ...") 
    List<MyEntity> myQuery(Pageable p); 
} 

Auf der anderen Seite, die findAll() Methode, die mit PagingAndSortingRepository kehrt kommt ein Iterable (und ich nehme an, dass die Daten nicht in den Speicher geladen werden).

Ist es möglich, benutzerdefinierte Abfragen zu definieren, die auch Iterable zurückgeben und/oder nicht alle Daten gleichzeitig in den Speicher laden?

Gibt es Alternativen zum Umgang mit großen Tischen?

+0

'List' implementiert die' Iterable'-Schnittstelle, sodass Ihre benutzerdefinierte Abfrage-Methode ein 'Iterable' zurückgibt. – zagyi

+0

Ich nehme an, dass Spring Data nicht alles im Speicher lädt, wenn ich findAll() verwende, bin ich falsch? Ich werde die Frage bearbeiten. –

+0

Die [zugrunde liegende Implementierung] (https://github.com/SpringSource/spring-data-jpa/blob/master/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java#L247) ruft einfach eine Liste ab, also ist es nicht so ausgefeilt. – zagyi

Antwort

9

Hier haben wir die klassische Antwort: es kommt darauf an. Da die Implementierung der Methode speicherspezifisch ist, hängen wir von der zugrunde liegenden Store-API ab. Im Falle von JPA gibt es keine Möglichkeit, Streaming-Zugriff bereitzustellen, da ….getResultList() eine List zurückgibt. Daher stellen wir auch die List dem Client zur Verfügung, da speziell JPA-Entwickler mit Listen arbeiten können. Für JPA ist die Paginierungs-API die einzige Option.

Für einen Speicher wie Neo4j unterstützen wir den Streaming-Zugriff, da die Repositorys sowohl CRUD-Methoden als auch die Ausführung von Finder-Methoden mit Iterable zurückliefern.

+0

Hallo Oliver, danke für die Erklärung. Ich habe ein Iterable erstellt, um das Paginierungskram zu abstrahieren. Wenn Sie etwas Zeit haben, würde ich mich über Rückmeldungen zum Code/Ansatz sehr freuen. Vielen Dank nochmal :) https://gist.github.com/josericardo/5102304 –

+1

Ich würde im Allgemeinen empfehlen, solche Dinge nicht zu tun.Es ist einfach, einen Wrapper zu übergeben, der Daten stillschweigend holt, aber Sie werden mit allen möglichen Problemen konfrontiert, da Sie die Sitzungsgrenze nicht wirklich kontrollieren können, so dass Sie auf 'LazyLoadingException' stoßen. Was ist los mit dem Zugriff auf eine "Page", über den Inhalt iterieren und wiederholen, wenn "Page.hasNext()" ist "wahr"? Dies macht zumindest deutlich, dass Sie Session-Grenzen auf der Repository-Ebene erhalten, es sei denn, Sie befinden sich in einer breiteren Bereichs-Transaktion. –

+0

Danke für das Feedback und die Zeit :) –

2

Die implementation von findAll() lädt einfach die gesamte Liste aller Entitäten in den Speicher. Sein Rückgabetyp Iterable impliziert nicht, dass er irgendeine Art von Cursorbearbeitung auf Datenbankebene implementiert.

Auf der anderen Seite Ihrer benutzerdefinierten myQuery(Pageable) Methode nur eine Seite im Wert von Einheiten geladen werden kann, weil die erzeugte Umsetzung seine Pageable Parameter ehrt. Sie können den Rückgabetyp entweder als Page oder List deklarieren. Im letzteren Fall erhalten Sie immer noch die gleiche (beschränkte) Anzahl von Entitäten, aber nicht die Metadaten, die zusätzlich eine Page tragen würden.

Sie haben also im Grunde genommen das Richtige getan, um das Laden aller Entitäten in den Speicher Ihrer benutzerdefinierten Abfrage zu vermeiden.

Bitte überprüfen Sie die related documentation here.

+0

Der zweite Link ist unterbrochen. Jetzt ist es https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.special-parameters – kolobok

Verwandte Themen