API GraphQL dengan Spring Boot · Pelajaran

Melaksanakan Pengumpulan Kelompok dan Penyimpanan Cache

Sepadukan DataLoaders ke dalam penyelesai Spring Boot anda untuk mengoptimumkan pengambilan data dan mengurangkan perjalanan ulang-alik ke pangkalan data.

Pelajaran 3 daripada 411 langkah

Melaksanakan Pengumpulan Kelompok dan Penyimpanan Cache ialah pelajaran API GraphQL dengan Spring Boot percuma di CoddyKit. Ini ialah pelajaran 3 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran API GraphQL dengan Spring Boot, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus API GraphQL dengan Spring Boot merangkumi sejumlah 4 pelajaran.

DataLoaders: Masa untuk Melaksanakan!

Selamat datang kembali! Dalam pelajaran terdahulu, kami mempelajari masalah N+1 dan cara DataLoaders menyediakan penyelesaian elegan melalui pengumpulan berkumpulan dan penyimpanan cache.

Hari ini, kita akan melaksanakan dan mengintegrasikan DataLoaders ke dalam aplikasi Spring Boot GraphQL. Kita akan melihat cara mentakrifkan BatchLoader, mendaftarkannya dan menggunakannya dalam penyelesai GraphQL.

Mensimulasikan Perkhidmatan Data

Pertama sekali, mari kita sediakan perkhidmatan olok-olok ringkas yang mensimulasikan pengambilan pengguna daripada pangkalan data. Perkhidmatan ini akan dipanggil oleh DataLoaders kita.

Perhatikan System.out.println, yang akan membantu kita memerhatikan masa panggilan 'pangkalan data' sebenar berlaku dan menunjukkan pengumpulan berkumpulan kemudian.

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.");
  }
}

Antara Muka BatchLoader

Teras mekanisme pengumpulan DataLoader ialah antara muka BatchLoader. Antara muka ini mentakrifkan satu kaedah: load(List<K> keys).

  • Ia menerima senarai kunci, contohnya ID pengguna.
  • Ia mengembalikan CompletionStage, iaitu objek yang menyerupai future, yang mengandungi senarai nilai, contohnya pengguna.
  • Yang penting, kaedah ini dipanggil sekali untuk semua kunci yang diminta dalam tempoh singkat, supaya anda boleh mendapatkannya melalui satu operasi yang dioptimumkan, seperti satu pertanyaan pangkalan data.

Melaksanakan BatchLoader Anda

Sekarang, mari kita cipta UserBatchLoader kita. Ia akan melaksanakan antara muka BatchLoader<String, User>, bermaksud ia menerima String, iaitu ID pengguna, sebagai kunci dan mengembalikan objek User.

Ia menggunakan MockUserService kita untuk melaksanakan pengambilan berkumpulan sebenar.

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

Dalam aplikasi Spring Boot GraphQL, tika DataLoader diuruskan dalam DataLoaderRegistry. Pendaftaran ini bertindak sebagai bekas untuk semua DataLoaders yang tersedia semasa pelaksanaan permintaan GraphQL.

  • Setiap DataLoader didaftarkan dengan nama unik, contohnya "userDataLoader".
  • Penyelesai mendapatkan DataLoader yang diperlukan daripada pendaftaran ini menggunakan namanya.
  • Spring for GraphQL biasanya mengurus kitar hayat dan skop pendaftaran ini bagi setiap permintaan.

Menyediakan DataLoaders

Beginilah cara anda mencipta tika DataLoader daripada BatchLoader dan mendaftarkannya dalam DataLoaderRegistry. Persediaan ini penting supaya DataLoaders boleh dicapai oleh penyelesai anda.

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

Menggunakan DataLoader dalam Penyelesai

Setelah DataLoader anda didaftarkan, anda boleh menggunakannya dalam penyelesai GraphQL. Daripada memanggil perkhidmatan secara terus, anda akan memanggil dataLoader.load(id).

  • Kaedah load() mengembalikan CompletionStage, bukan objek secara terus.
  • DataLoader mengumpulkan semua panggilan load() dalam bingkai pelaksanaan semasa sebelum menghantarnya kepada BatchLoader.
  • Spring for GraphQL menghantar DataLoaders secara automatik pada akhir kitaran pengambilan data.

Integrasi Penyelesai dalam Tindakan

Contoh ini mensimulasikan pertanyaan GraphQL yang meminta berbilang ID pengguna. Perhatikan mesej "Panggilan DB" dalam output untuk melihat cara DataLoaders mengumpulkan permintaan ini menjadi satu operasi, walaupun permintaan tersebut kelihatan berasingan dalam logik penyelesai.

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

Penyimpanan Cache Terbina Dalam DataLoader

Selain pengumpulan berkumpulan, DataLoaders juga menyediakan penyimpanan cache mengikut skop permintaan secara terbina dalam. Maksudnya:

  • Jika dataLoader.load("1") dipanggil beberapa kali dalam permintaan GraphQL yang sama, fungsi pengambilan BatchLoader untuk ID "1" hanya akan dipanggil sekali.
  • Panggilan seterusnya untuk ID yang sama dalam permintaan tersebut akan mengembalikan hasil yang telah diambil dan dicache.
  • Ini menghalang panggilan pangkalan data berulang untuk data yang sama dalam satu operasi GraphQL, lalu meningkatkan prestasi dengan lebih lanjut.

Semak Kefahaman Anda

Anda telah mempelajari cara melaksanakan DataLoaders untuk pengumpulan berkumpulan dan penyimpanan cache. Mari uji pengetahuan anda!

Imbas Kembali: Pengumpulan Berkumpulan dan Penyimpanan Cache

Syabas! Anda telah berjaya mempelajari cara melaksanakan DataLoaders dalam Spring Boot GraphQL.

  • Kami mencipta MockUserService untuk mensimulasikan pengambilan data.
  • Kami membina UserBatchLoader untuk mengendalikan pengumpulan berbilang permintaan ID.
  • Kami melihat cara memulakan dan mendaftarkan tika DataLoader dalam DataLoaderRegistry.
  • Akhir sekali, kami mengintegrasikan DataLoaders ke dalam penyelesai dan memerhatikan cara permintaan dikumpulkan serta cara penyimpanan cache menghalang panggilan berulang.

Dengan menggunakan DataLoaders, anda mengoptimumkan prestasi API GraphQL anda dengan ketara, khususnya ketika mengendalikan graf data yang kompleks dan objek bersarang.

Percuma untuk bermula

Pelajari API GraphQL dengan Spring Boot dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
12
Pelajaran
48

Soalan Lazim

Adakah pelajaran “Melaksanakan Pengumpulan Kelompok dan Penyimpanan Cache” percuma?

Ya — teks penuh “Melaksanakan Pengumpulan Kelompok dan Penyimpanan Cache” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus API GraphQL dengan Spring Boot, tingkat taraf kepada CoddyKit PRO. Kursus API GraphQL dengan Spring Boot merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Melaksanakan Pengumpulan Kelompok dan Penyimpanan Cache”?

Sepadukan DataLoaders ke dalam penyelesai Spring Boot anda untuk mengoptimumkan pengambilan data dan mengurangkan perjalanan ulang-alik ke pangkalan data. Anda berlatih API GraphQL dengan Spring Boot menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan API GraphQL dengan Spring Boot?

Tiada pengalaman terdahulu diperlukan. Pembelajaran API GraphQL dengan Spring Boot di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 3 daripada 4.

Berapa lamakah pelajaran “Melaksanakan Pengumpulan Kelompok dan Penyimpanan Cache” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran API GraphQL dengan Spring Boot ini?

Ya. Setiap pelajaran API GraphQL dengan Spring Boot menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Masalah N+1 Diterangkan
  2. Pengenalan kepada DataLoaders
  3. Melaksanakan Pengumpulan Kelompok dan Penyimpanan Cache
  4. DataLoaders dengan Konteks Spring dan Tak Segerak
← Kembali ke API GraphQL dengan Spring Boot