打开文档导航
R2D1 / 文档

开始使用

R2D1 的设置从两个后端选择开始,之后进入一条通用 API 流程。选择完整文档的存储位置和索引字段的存储位置,然后用这两个 store 配置集合 facade。

1. 选择文档存储

DocumentStore 是完整序列化文档、按标识读取和逻辑存在性的权威来源。请选择一个:

  • R2 DocumentStore 通过 AWS SDK 异步客户端将文档存储在 Cloudflare R2。
  • Filesystem DocumentStore 使用原子替换保存规范的本地文档。

2. 选择索引存储

IndexStore 是文档标识和显式索引字段的可重建投影。请选择一个:

  • D1 IndexStore 通过 Java 异步 HttpClient 使用 Cloudflare D1 REST API。
  • JDBC IndexStore 通过应用拥有的 DataSource 支持 H2、HSQLDB 和本地 SQLite。

这些选择形成 R2 + D1、R2 + JDBC、Filesystem + D1 和 Filesystem + JDBC 四种组合,但不会产生四套不同的集合 API。

3. 添加所需模块

核心 artifact 提供通用 API 以及 Cloudflare R2/D1 适配器:

dependencies {
    implementation("dev.nexcraft:r2d1:<version>")
}

只添加应用实际使用的集成模块:

dependencies {
    implementation("dev.nexcraft:r2d1-filesystem:<version>")
    implementation("dev.nexcraft:r2d1-jdbc:<version>")
    implementation("dev.nexcraft:r2d1-micronaut:<version>")
}

JDBC 驱动由应用提供,r2d1-jdbc 不会将其打包。完整的模块表和所有权规则请参阅 Configuration.

4. 定义文档

为一个非空 String 成员添加 @Id 作为标识,并为需要写入索引的字段添加 @Index。只有显式索引的字段才能参与过滤和排序。

import dev.nexcraft.r2d1.annotation.Document;
import dev.nexcraft.r2d1.annotation.Id;
import dev.nexcraft.r2d1.annotation.Index;

@Document("users")
public record User(
    @Id String id,
    @Index String country,
    @Index long score,
    String name) {}

R2D1 不选择 JSON library。请提供 DocumentCodec,将 domain object 序列化为 StoredDocument,并在集合生成结果时再次反序列化。

5. 配置通用集合 API

下面的示例将适配器创建留给应用,以便清楚展示两个存储角色。documentStore、indexStore 和 documentCodec 都由应用拥有。

import dev.nexcraft.r2d1.DocumentCodec;
import dev.nexcraft.r2d1.PersistenceCollectionFactory;
import dev.nexcraft.r2d1.R2D1;
import dev.nexcraft.r2d1.R2D1Collection;
import dev.nexcraft.r2d1.spi.DocumentStore;
import dev.nexcraft.r2d1.spi.IndexStore;

DocumentStore documentStore = applicationDocumentStore;
IndexStore indexStore = applicationIndexStore;
DocumentCodec documentCodec = applicationDocumentCodec;

R2D1 database =
    R2D1.builder()
        .collectionFactory(
            new PersistenceCollectionFactory(
                documentStore, indexStore, documentCodec, indexStore::initialize))
        .build();

R2D1Collection<User> users = database.collection(User.class);

打开集合时,R2D1 会先初始化或验证集合 metadata,然后返回集合。factory 不会接管 store、codec 或调用方拥有的执行资源。

6. put、get 和 delete

User user = new User("user-123", "NZ", 42, "Ada");
users.put(user);

Optional<User> stored = users.get("user-123");

users.delete("user-123");
Optional<User> absent = users.get("user-123");

put 使用 @Id 值创建或替换文档。get 读取权威文档存储,删除不存在的标识不会产生效果。

7. 运行索引查询

import dev.nexcraft.r2d1.Page;
import dev.nexcraft.r2d1.SortDirection;

Page<User> first =
    users.query()
        .where("country")
        .eq("NZ")
        .sortBy("score", SortDirection.DESC)
        .limit(20)
        .fetch();

if (first.nextCursor() != null) {
  Page<User> second =
      users.query()
          .where("country")
          .eq("NZ")
          .sortBy("score", SortDirection.DESC)
          .limit(20)
          .after(first.nextCursor())
          .fetch();
}

cursor 是不透明值。请求下一页时保持相同的 filter 和 sort。支持的比较运算符和排序规则请参阅 Querying;在生产环境使用两个 store 前,请阅读 Consistency and Recovery.