Batching en caching implementeren
Integreer DataLoaders in uw Spring Boot-resolvers om het ophalen van gegevens te optimaliseren en het aantal database-roundtrips te verminderen.
Batching en caching implementeren is een gratis GraphQL-API's met Spring Boot-les op CoddyKit. Dit is les 3 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject GraphQL-API's met Spring Boot. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus GraphQL-API's met Spring Boot bevat in totaal 4 lessen.
DataLoaders: tijd om ze te implementeren!
Welkom terug! In eerdere lessen hebben we het N+1-probleem besproken en geleerd hoe DataLoaders een elegante oplossing bieden door bundelen en cachen.
Vandaag gaan we praktisch aan de slag en integreren we DataLoaders in een Spring Boot GraphQL-toepassing. We bekijken hoe je een BatchLoader definieert, registreert en gebruikt in onze GraphQL-resolvers.
Een gegevensservice simuleren
Eerst stellen we een eenvoudige nepservice in die simuleert dat gebruikers uit een database worden opgehaald. Deze service wordt door onze DataLoaders aangeroepen.
Let op de System.out.println. Daarmee kunnen we zien wanneer de daadwerkelijke 'databaseaanroep' plaatsvindt, zodat we het bundelen later kunnen demonstreren.
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
// A simple User data class
class User {
String id;
String name;
User(String id, String name) {
this.id = id; this.name = name;
}
public String getId() { return id; }
public String getName() { return name; }
}
// Mock service to fetch users (simulates DB call)
class MockUserService {
private final Map<String, User> users = Map.of(
"1", new User("1", "Alice"),
"2", new User("2", "Bob"),
"3", new User("3", "Charlie"),
"4", new User("4", "David")
);
public List<User> findAllByIds(List<String> ids) {
System.out.println("DB Call: Fetching users for IDs: " + ids);
return ids.stream()
.map(users::get)
.filter(user -> user != null)
.collect(Collectors.toList());
}
}
public class Main {
public static void main(String[] args) {
MockUserService service = new MockUserService();
List<User> foundUsers = service.findAllByIds(List.of("1", "3"));
System.out.println("Found: " + foundUsers.size() + " users.");
}
}De BatchLoader-interface
De kern van het bundelmechanisme van DataLoader is de interface BatchLoader. Deze definieert één methode: load(List<K> keys).
- De methode accepteert een lijst met sleutels (bijvoorbeeld gebruikers-ID's).
- De methode retourneert een
CompletionStage(een future-achtig object) met een lijst waarden (bijvoorbeeld gebruikers). - Belangrijk: deze methode wordt één keer aangeroepen voor alle sleutels die binnen een korte periode zijn opgevraagd. Zo kun je ze ophalen in één geoptimaliseerde bewerking, bijvoorbeeld met één databasequery.
Je BatchLoader implementeren
Nu maken we onze UserBatchLoader. Deze implementeert de interface BatchLoader<String, User>, wat betekent dat de loader een String (gebruikers-ID) als sleutel accepteert en een User-object retourneert.
De loader gebruikt onze MockUserService om de daadwerkelijke batchophaling uit te voeren.
import org.dataloader.BatchLoader;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
// (Assume User and MockUserService are defined elsewhere)
// For runnable example, they would be in the same file.
public class UserBatchLoader implements BatchLoader<String, User> {
private final MockUserService userService;
public UserBatchLoader(MockUserService userService) {
this.userService = userService;
}
@Override
public CompletionStage<List<User>> load(List<String> userIds) {
// This method is called once with all requested IDs.
// We delegate to our mock service to fetch them in one go.
return CompletableFuture.supplyAsync(
() -> userService.findAllByIds(userIds)
);
}
}
public class Main {
public static void main(String[] args) {
MockUserService userService = new MockUserService();
UserBatchLoader batchLoader = new UserBatchLoader(userService);
System.out.println("UserBatchLoader created!");
}
}Het DataLoaderRegistry
In een Spring Boot GraphQL-toepassing worden DataLoader-instanties beheerd binnen een DataLoaderRegistry. Dit register fungeert als container voor alle DataLoaders die tijdens de uitvoering van een GraphQL-verzoek beschikbaar zijn.
- Elke DataLoader wordt geregistreerd met een unieke naam (bijvoorbeeld "userDataLoader").
- Resolvers halen de benodigde DataLoader met de naam op uit dit register.
- Spring for GraphQL beheert doorgaans de levensduur en het bereik van dit register per verzoek.
DataLoaders instellen
Zo maak je een DataLoader-instantie vanuit je BatchLoader en registreer je die in een DataLoaderRegistry. Deze configuratie is essentieel om DataLoaders beschikbaar te maken voor je resolvers.
import org.dataloader.DataLoader;
import org.dataloader.DataLoaderRegistry;
// (Assume User, MockUserService, UserBatchLoader are defined)
public class Main {
public static void main(String[] args) {
MockUserService userService = new MockUserService();
UserBatchLoader userBatchLoader = new UserBatchLoader(userService);
// Create a DataLoader instance
DataLoader<String, User> userDataLoader =
DataLoader.newDataLoader(userBatchLoader);
// Register it in a DataLoaderRegistry
DataLoaderRegistry registry = new DataLoaderRegistry();
registry.register("userDataLoader", userDataLoader);
System.out.println("DataLoader registered as 'userDataLoader'!");
// In a real app, this registry would be part of the GraphQLContext.
// Resolvers would then retrieve DataLoaders from it.
}
}DataLoader in resolvers gebruiken
Zodra je DataLoader is geregistreerd, kun je deze gebruiken in je GraphQL-resolvers. In plaats van je service rechtstreeks aan te roepen, roep je dataLoader.load(id) aan.
- De methode
load()retourneert eenCompletionStage, niet het object zelf. - De DataLoader verzamelt alle aanroepen van
load()binnen het huidige uitvoeringsframe voordat deze naar deBatchLoaderworden doorgestuurd. - Spring for GraphQL stuurt de DataLoaders automatisch door aan het einde van een cyclus voor het ophalen van gegevens.
Resolverintegratie in actie
Dit voorbeeld simuleert een GraphQL-query waarin meerdere gebruikers-ID's worden opgevraagd. Let op het bericht "DB Call" in de uitvoer om te zien hoe DataLoaders deze verzoeken bundelen tot één bewerking, ook als ze in de resolverlogica afzonderlijk lijken.
import org.dataloader.DataLoader;
import org.dataloader.DataLoaderRegistry;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.stream.Collectors;
// User, MockUserService, UserBatchLoader definitions (from previous scenes)
class User {
String id; String name;
User(String id, String name) { this.id = id; this.name = name; }
public String getId() { return id; }
public String getName() { return name; }
}
class MockUserService {
private final Map<String, User> users = Map.of(
"1", new User("1", "Alice"), "2", new User("2", "Bob"),
"3", new User("3", "Charlie"), "4", new User("4", "David")
);
public List<User> findAllByIds(List<String> ids) {
System.out.println("DB Call: Fetching users for IDs: " + ids);
return ids.stream().map(users::get)
.filter(user -> user != null).collect(Collectors.toList());
}
}
class UserBatchLoader implements BatchLoader<String, User> {
private final MockUserService userService;
public UserBatchLoader(MockUserService userService) { this.userService = userService; }
@Override
public CompletionStage<List<User>> load(List<String> userIds) {
return CompletableFuture.supplyAsync(() -> userService.findAllByIds(userIds));
}
}
// Simulate a GraphQL Query Resolver method
public class UserResolver {
private final DataLoaderRegistry dataLoaderRegistry;
public UserResolver(DataLoaderRegistry registry) {
this.dataLoaderRegistry = registry;
}
public CompletionStage<User> getUserById(String id) {
DataLoader<String, User> userDataLoader =
dataLoaderRegistry.getDataLoader("userDataLoader");
return userDataLoader.load(id);
}
public static void main(String[] args) {
MockUserService userService = new MockUserService();
UserBatchLoader userBatchLoader = new UserBatchLoader(userService);
DataLoader<String, User> userDataLoader =
DataLoader.newDataLoader(userBatchLoader);
DataLoaderRegistry registry = new DataLoaderRegistry();
registry.register("userDataLoader", userDataLoader);
UserResolver resolver = new UserResolver(registry);
System.out.println("Requesting User 1 and User 2 concurrently...");
// Simulate two concurrent GraphQL field fetches
CompletableFuture<User> user1Future =
(CompletableFuture<User>) resolver.getUserById("1");
CompletableFuture<User> user2Future =
(CompletableFuture<User>) resolver.getUserById("2");
CompletableFuture.allOf(user1Future, user2Future)
.thenRun(() -> {
try {
System.out.println("Fetched User 1: " + user1Future.join().getName());
System.out.println("Fetched User 2: " + user2Future.join().getName());
} catch (Exception e) {
e.printStackTrace();
}
// For this manual demo, we dispatch the DataLoader.
// In Spring GraphQL, this is handled automatically.
userDataLoader.dispatch();
}).join();
}
}Ingebouwde caching van DataLoader
Naast bundelen bieden DataLoaders standaard ook caching binnen het bereik van een verzoek. Dat betekent het volgende:
- Als
dataLoader.load("1")meerdere keren binnen hetzelfde GraphQL-verzoek wordt aangeroepen, wordt de ophaalfunctie van deBatchLoadervoor ID "1" maar één keer aangeroepen. - Volgende aanroepen voor dezelfde ID binnen dat verzoek retourneren het al opgehaalde resultaat uit de cache.
- Dit voorkomt overbodige databaseaanroepen voor dezelfde gegevens binnen één GraphQL-bewerking en verbetert de prestaties verder.
Controleer je begrip
Je hebt geleerd hoe je DataLoaders implementeert voor bundelen en cachen. Test nu je kennis!
Samenvatting: bundelen en cachen
Goed gedaan! Je hebt geleerd hoe je DataLoaders implementeert in Spring Boot GraphQL.
- We hebben een
MockUserServicegemaakt om het ophalen van gegevens te simuleren. - We hebben een
UserBatchLoadergebouwd om meerdere ID-verzoeken te bundelen. - We hebben gezien hoe je
DataLoader-instanties initialiseert en registreert in eenDataLoaderRegistry. - Tot slot hebben we DataLoaders in een resolver geïntegreerd en gezien hoe verzoeken worden gebundeld en hoe caching overbodige aanroepen voorkomt.
Door DataLoaders te gebruiken optimaliseer je de prestaties van je GraphQL API aanzienlijk, vooral bij complexe gegevensgrafieken en geneste objecten.
Leer GraphQL-API's met Spring Boot met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 12
- Lessen
- 48
Veelgestelde vragen
Is de les “Batching en caching implementeren” gratis?
Ja — de volledige tekst van “Batching en caching implementeren” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus GraphQL-API's met Spring Boot wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus GraphQL-API's met Spring Boot bevat in totaal 4 lessen.
Wat leer ik in “Batching en caching implementeren”?
Integreer DataLoaders in uw Spring Boot-resolvers om het ophalen van gegevens te optimaliseren en het aantal database-roundtrips te verminderen. Je oefent met GraphQL-API's met Spring Boot door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met GraphQL-API's met Spring Boot te beginnen?
Ervaring vooraf is niet nodig. GraphQL-API's met Spring Boot op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 3 van 4.
Hoe lang duurt de les “Batching en caching implementeren”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over GraphQL-API's met Spring Boot?
Ja. Elke les over GraphQL-API's met Spring Boot bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Het N+1-probleem uitgelegd
- Kennismaken met GraphQL DataLoaders
- Batching en caching implementeren
- DataLoaders met Spring Context en async verwerking