GraphQL-rajapinnat Spring Bootilla · Oppitunti

Eräajon ja välimuistin toteuttaminen

Integroikaa DataLoaderit Spring Boot -resolvareihin tietojen haun optimoimiseksi ja tietokantakierrosten vähentämiseksi.

Oppitunti 3/411 vaihetta

Eräajon ja välimuistin toteuttaminen on ilmainen GraphQL-rajapinnat Spring Bootilla-oppitunti CoddyKitissä. Tämä on oppitunti 3/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu GraphQL-rajapinnat Spring Bootilla-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. GraphQL-rajapinnat Spring Bootilla-kurssilla on yhteensä 4 oppituntia.

DataLoaderit: aika toteuttaa!

Tervetuloa takaisin! Aiemmilla oppitunneilla opimme N+1-ongelmasta ja siitä, miten DataLoaderit tarjoavat elegantin ratkaisun eräkäsittelyn ja välimuistin avulla.

Tänään pääsette käytännön harjoitteluun ja integroitte DataLoaderit Spring Boot GraphQL -sovellukseen. Näette, miten BatchLoader määritellään ja rekisteröidään sekä miten sitä käytetään GraphQL-resolvereissa.

Datalähteen simulointi

Ensin määritetään yksinkertainen mock-palvelu, joka simuloi käyttäjien hakemista tietokannasta. DataLoaderit kutsuvat tätä palvelua.

Huomioikaa System.out.println, jonka avulla voitte tarkkailla, milloin varsinainen ”tietokanta”-kutsu tapahtuu. Näin eräkäsittely tulee myöhemmin näkyviin.

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-rajapinta

DataLoaderin eräkäsittelymekanismin ydin on BatchLoader-rajapinta. Se määrittelee yhden metodin: load(List<K> keys).

  • Se ottaa vastaan avainten listan (esimerkiksi käyttäjätunnukset).
  • Se palauttaa arvojen listan sisältävän CompletionStage-olion (futuurin kaltaisen olion).
  • Keskeistä on, että tätä metodia kutsutaan kerran kaikille lyhyen ajanjakson aikana pyydetyille avaimille. Näin ne voidaan hakea yhdellä optimoidulla operaatiolla, kuten yhdellä tietokantakyselyllä.

BatchLoaderin toteuttaminen

Luodaan nyt UserBatchLoader. Se toteuttaa BatchLoader<String, User>-rajapinnan, mikä tarkoittaa, että se ottaa avaimeksi String-tyyppisen arvon (käyttäjätunnuksen) ja palauttaa User-olion.

Se käyttää MockUserService-palvelua varsinaisen erähaun suorittamiseen.

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

Spring Boot GraphQL -sovelluksessa DataLoader-instansseja hallitaan DataLoaderRegistry-rekisterissä. Rekisteri toimii säilönä kaikille GraphQL-pyynnön suorituksen aikana käytettävissä oleville DataLoadereille.

  • Jokainen DataLoader rekisteröidään yksilöllisellä nimellä (esimerkiksi "userDataLoader").
  • Resolverit hakevat tarvitsemansa DataLoaderin tästä rekisteristä sen nimen perusteella.
  • Spring for GraphQL käsittelee yleensä tämän rekisterin elinkaaren ja käyttöalueen pyyntökohtaisesti.

DataLoadereiden määrittäminen

Näin luotte BatchLoader-oliosta DataLoader-instanssin ja rekisteröitte sen DataLoaderRegistry-rekisteriin. Tämä määritys on ratkaisevan tärkeä, jotta resolverit voivat käyttää DataLoadereita.

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.
  }
}

DataLoaderin käyttäminen resolvereissa

Kun DataLoader on rekisteröity, voitte käyttää sitä GraphQL-resolvereissa. Sen sijaan, että kutsuisitte palvelua suoraan, kutsutte dataLoader.load(id)-metodia.

  • load()-metodi palauttaa CompletionStage-olion, ei suoraa oliota.
  • DataLoader kerää kaikki load()-kutsut nykyisen suorituskehyksen aikana ennen niiden lähettämistä BatchLoader-käsittelijälle.
  • Spring for GraphQL lähettää DataLoaderit automaattisesti datanhakusyklin lopussa.

Resolver-integraatio käytännössä

Tämä esimerkki simuloi GraphQL-kyselyä, jossa pyydetään useiden käyttäjien tunnuksia. Seuratkaa tulosteen "DB Call" -viestiä nähdäksenne, miten DataLoaderit yhdistävät nämä pyynnöt yhdeksi operaatioksi, vaikka ne näyttävät resolverin logiikassa erillisiltä.

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();
  }
}

DataLoaderin sisäinen välimuisti

Eräkäsittelyn lisäksi DataLoaderit tarjoavat valmiiksi pyynnön laajuisen välimuistin. Tämä tarkoittaa seuraavaa:

  • Jos dataLoader.load("1") kutsutaan useita kertoja saman GraphQL-pyynnön aikana, BatchLoader-käsittelijän hakufunktiota tunnukselle "1" kutsutaan vain kerran.
  • Saman tunnuksen myöhemmät kutsut kyseisen pyynnön aikana palauttavat jo haetun, välimuistiin tallennetun tuloksen.
  • Tämä estää saman datan tarpeettomat tietokantakutsut yhden GraphQL-operaation aikana ja parantaa suorituskykyä entisestään.

Testatkaa ymmärrystänne

Olette oppineet toteuttamaan DataLoadereita eräkäsittelyä ja välimuistia varten. Testataanpa tietonne!

Kertaus: eräkäsittely ja välimuisti

Hienoa työtä! Olette oppineet toteuttamaan DataLoadereita Spring Boot GraphQL -sovelluksessa.

  • Loimme MockUserService-palvelun simuloimaan datan hakemista.
  • Rakensimme UserBatchLoader-käsittelijän useiden tunnuspyyntöjen eräkäsittelyä varten.
  • Näimme, miten DataLoader-instanssit alustetaan ja rekisteröidään DataLoaderRegistry-rekisteriin.
  • Lopuksi integroimme DataLoaderit resolveriin ja tarkkailimme, miten pyynnöt yhdistetään eriksi ja miten välimuisti estää tarpeettomat kutsut.

DataLoadereiden avulla GraphQL API:n suorituskykyä voidaan optimoida merkittävästi, erityisesti käsiteltäessä monimutkaisia datagraafeja ja sisäkkäisiä olioita.

Aloita maksutta

Opi GraphQL-rajapinnat Spring Bootilla tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
12
Oppitunnit
48

Usein kysytyt kysymykset

Onko oppitunti ”Eräajon ja välimuistin toteuttaminen” ilmainen?

Kyllä – oppitunnin ”Eräajon ja välimuistin toteuttaminen” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko GraphQL-rajapinnat Spring Bootilla-kurssin, päivitä CoddyKit PROhon. GraphQL-rajapinnat Spring Bootilla-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Eräajon ja välimuistin toteuttaminen”?

Integroikaa DataLoaderit Spring Boot -resolvareihin tietojen haun optimoimiseksi ja tietokantakierrosten vähentämiseksi. Harjoittelet GraphQL-rajapinnat Spring Bootilla-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni GraphQL-rajapinnat Spring Bootilla-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin GraphQL-rajapinnat Spring Bootilla-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 3/4.

Kuinka kauan ”Eräajon ja välimuistin toteuttaminen”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä GraphQL-rajapinnat Spring Bootilla-oppitunnilla?

Kyllä. Jokainen GraphQL-rajapinnat Spring Bootilla-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. N+1-ongelman selitys
  2. GraphQL DataLoaderien esittely
  3. Eräajon ja välimuistin toteuttaminen
  4. DataLoaderit Spring-kontekstin ja asynkronisuuden kanssa
← Takaisin: GraphQL-rajapinnat Spring Bootilla