Implementering af batchbehandling og caching
Integrér DataLoaders i dine Spring Boot-resolvere for at optimere datahentning og reducere antallet af rundture til databasen.
Implementering af batchbehandling og caching er en gratis GraphQL-API'er med Spring Boot-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i GraphQL-API'er med Spring Boot, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. GraphQL-API'er med Spring Boot-kurset indeholder 4 lektioner i alt.
DataLoaders: Tid til implementering!
Velkommen tilbage! I tidligere lektioner lærte vi om N+1-problemet, og hvordan DataLoaders giver en elegant løsning gennem batching og caching.
I dag arbejder vi praktisk og integrerer DataLoaders i en Spring Boot GraphQL-applikation. Vi ser, hvordan man definerer en BatchLoader, registrerer den og bruger den i vores GraphQL-resolvere.
Simulering af en datatjeneste
Først opsætter vi en enkel mocktjeneste, der simulerer hentning af brugere fra en database. Denne tjeneste vil blive kaldt af vores DataLoaders.
Bemærk System.out.println, som hjælper os med at se, hvornår det faktiske 'database'-kald sker, så batching demonstreres senere.
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.");
}
}BatchLoader-interfacet
Kernen i DataLoaders' batching-mekanisme er interfacet BatchLoader. Det definerer én metode: load(List<K> keys).
- Den modtager en liste med nøgler (f.eks. bruger-id'er).
- Den returnerer en
CompletionStage(et future-lignende objekt) med en liste af værdier (f.eks. brugere). - Det afgørende er, at denne metode kaldes én gang for alle nøgler, der anmodes om inden for et kort tidsrum, så du kan hente dem i én optimeret handling (f.eks. én databaseforespørgsel).
Implementering af din BatchLoader
Lad os nu oprette vores UserBatchLoader. Den implementerer interfacet BatchLoader<String, User>, hvilket betyder, at den tager en String (bruger-id) som nøgle og returnerer et User-objekt.
Den bruger vores MockUserService til at udføre den faktiske batchhentning.
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!");
}
}DataLoaderRegistry
I en Spring Boot GraphQL-applikation administreres DataLoader-instanser i en DataLoaderRegistry. Dette register fungerer som en beholder for alle DataLoaders, der er tilgængelige under udførelsen af en GraphQL-forespørgsel.
- Hver DataLoader registreres med et entydigt navn (f.eks. "userDataLoader").
- Resolvere henter den nødvendige DataLoader fra dette register ved hjælp af dens navn.
- Spring for GraphQL håndterer typisk registrets levetid og scope pr. forespørgsel.
Opsætning af DataLoaders
Her kan du se, hvordan du opretter en DataLoader-instans fra din BatchLoader og registrerer den i en DataLoaderRegistry. Denne opsætning er afgørende for at gøre DataLoaders tilgængelige for dine resolvere.
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.
}
}Brug af DataLoader i resolvere
Når din DataLoader er registreret, kan du bruge den i dine GraphQL-resolvere. I stedet for at kalde din tjeneste direkte kalder du dataLoader.load(id).
- Metoden
load()returnerer enCompletionStage, ikke det direkte objekt. - DataLoader indsamler alle kald til
load()inden for den aktuelle udførelsesramme, før den sender dem videre tilBatchLoader. - Spring for GraphQL sender automatisk DataLoaders videre ved afslutningen af en datahentningscyklus.
Resolver-integration i praksis
Dette eksempel simulerer en GraphQL-forespørgsel, hvor der anmodes om flere bruger-id'er. Hold øje med meddelelsen "DB Call" i outputtet for at se, hvordan DataLoaders samler disse forespørgsler i én handling, selvom de ser separate ud i resolverlogikken.
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();
}
}DataLoaders' indbyggede caching
Ud over batching tilbyder DataLoaders også caching begrænset til forespørgslen direkte fra start. Det betyder:
- Hvis
dataLoader.load("1")kaldes flere gange inden for den samme GraphQL-forespørgsel, bliverBatchLoader's hente-funktion for id'et "1" kun kaldt én gang. - Efterfølgende kald for det samme id inden for den pågældende forespørgsel returnerer det allerede hentede (cachede) resultat.
- Det forhindrer overflødige databasekald for de samme data i en enkelt GraphQL-handling og forbedrer dermed ydeevnen yderligere.
Tjek din forståelse
Du har lært, hvordan man implementerer DataLoaders til batching og caching. Lad os teste din viden!
Opsummering: Batching og caching
Godt gået! Du har lært at implementere DataLoaders i Spring Boot GraphQL.
- Vi oprettede en
MockUserServicefor at simulere datahentning. - Vi byggede en
UserBatchLoadertil at håndtere batching af flere id-forespørgsler. - Vi så, hvordan man initialiserer og registrerer
DataLoader-instanser i enDataLoaderRegistry. - Til sidst integrerede vi DataLoaders i en resolver og så, hvordan forespørgsler samles, og hvordan caching forhindrer overflødige kald.
Ved at bruge DataLoaders optimerer du din GraphQL-API's ydeevne betydeligt, især når du arbejder med komplekse datagrafer og indlejrede objekter.
Lær GraphQL-API'er med Spring Boot med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 12
- Lektioner
- 48
Ofte stillede spørgsmål
Er lektionen “Implementering af batchbehandling og caching” gratis?
Ja — hele teksten til “Implementering af batchbehandling og caching” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af GraphQL-API'er med Spring Boot-kurset, skal du opgradere til CoddyKit PRO. GraphQL-API'er med Spring Boot-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Implementering af batchbehandling og caching”?
Integrér DataLoaders i dine Spring Boot-resolvere for at optimere datahentning og reducere antallet af rundture til databasen. Du øver dig i GraphQL-API'er med Spring Boot med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på GraphQL-API'er med Spring Boot?
Der kræves ingen tidligere erfaring. GraphQL-API'er med Spring Boot på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.
Hvor lang tid tager lektionen “Implementering af batchbehandling og caching”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne GraphQL-API'er med Spring Boot-lektion?
Ja. Alle GraphQL-API'er med Spring Boot-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- N+1-problemet forklaret
- Introduktion til GraphQL DataLoaders
- Implementering af batchbehandling og caching
- DataLoaders med Spring Context og async