从 App Engine Datastore 迁移到 Datastore 模式 Firestore

本指南演示了如何从 App Engine Datastore 迁移到 Datastore 模式 Firestore(也称为 Datastore)。

Datastore 模式 Firestore 与 App Engine Datastore 类似,两者都引用同一底层 Datastore 服务。虽然 App Engine Datastore 只能通过 App Engine 旧版捆绑服务进行访问,但 Datastore 模式 Firestore 是一种独立 Google Cloud 产品,可通过 Cloud 客户端库访问它。

Datastore 模式 Firestore 还提供了一个免费层级,可让您管理可扩缩性极强的 NoSQL 文档数据库,并在将来灵活地迁移到 Cloud Run 或其他 Google Cloud 应用托管平台。

须知事项

  1. 查看不同的 Firestore 数据库模式,以确保了解适用于您的应用的最佳使用场景。请注意,本指南介绍了如何迁移到 Datastore 模式。

  2. 查看并了解 Datastore 模式 Firestore 的价格配额

    Datastore 模式 Firestore 提供具有每日上限的免费用量,另提供付费账号,拥有无限存储、读取和写入操作次数。App Engine 应用被停用后,不会产生任何流量产生费用,但如果超出免费配额上限,则 Datastore 使用量可能会计费。

  3. 在包含您的应用的项目中启用以下 API:

    • 用于存储和管理您的构建工件的 Artifact Registry API
    • Cloud Build API,用于持续构建、测试和部署应用。
    • Cloud Datastore API,用于从 App Engine 捆绑数据存储区迁移到 Datastore 模式 Firestore。

      启用 API

  4. 具有运行 Java 8 或 11 且已连接到 App Engine Datastore 服务的现有 App Engine 应用。

过程概览

概括来讲,从 App Engine Datastore 迁移到 Datastore 模式 Firestore 的过程包括以下步骤:

  1. 更新配置文件
  2. 更新 Java 应用
    1. 更新导入语句
    2. 修改应用访问 Datastore 服务的方式
    3. 获取 Datastore 生成的键
    4. 修改实体创建
  3. 提交事务
  4. 查询结果

更新配置文件

更新配置文件以使用 Datastore 模式客户端库

更新基准 Java 应用的 pom.xml 文件:

  1. 移除 App Engine SDK appengine-api-1.0-sdk 导入,如以下所示:

    <dependency>
      <groupId>com.google.appengine</groupId>
      <artifactId>appengine-api-1.0-sdk</artifactId>
      <version>2.0.4</version>
    </dependency>
    
  2. 添加 Datastore 客户端,如以下所示:

    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-datastore</artifactId>
      <!-- Use latest version -->
      <version>2.2.9</version>
    </dependency>
    

更新 Java 应用

更新导入语句

通过更新导入和初始化行来修改应用文件:

  1. 移除 App Engine Datastore com.google.appengine.api.datastore.* 的以下 App Engine 导入语句:

      import com.google.appengine.api.datastore.DatastoreService;
      import com.google.appengine.api.datastore.DatastoreServiceFactory;
      import com.google.appengine.api.datastore.Entity;
      import com.google.appengine.api.datastore.FetchOptions;
      import com.google.appengine.api.datastore.Query;
    
  2. 添加以下 Datastore 模式 Firestore com.google.cloud.datastore.* 导入:

      import com.google.cloud.Timestamp;
      import com.google.cloud.datastore.Datastore;
      import com.google.cloud.datastore.DatastoreOptions;
      import com.google.cloud.datastore.Entity;
      import com.google.cloud.datastore.Key;
      import com.google.cloud.datastore.FullEntity;
      import com.google.cloud.datastore.KeyFactory;
      import com.google.cloud.datastore.Query;
      import com.google.cloud.datastore.QueryResults;
      import com.google.cloud.datastore.StructuredQuery;
    

修改应用访问 Datastore 服务的方式

Datastore 模式 Firestore 使用 Datastore 类,而不是 DatastoreService。如需修改应用访问 Datastore 服务的方式,请执行以下操作:

  1. 找到使用 DatastoreServiceFactory.getDatastoreService() 方法的行,如以下所示:

    // Initialize a client
    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
    
  2. DatastoreServiceFactory.getDatastoreService() 替换为 DatastoreOptions.getDefaultInstance().getService() 方法,如以下所示:

    // Initialize a client
    Datastore datastore = DatastoreOptions.getDefaultInstance().getService();
    

获取 Datastore 生成的键

初始化客户端后,通过创建相应 Kind 的新 KeyFactory 来获取键,然后让 Datastore 为您生成一个键。如需获取 Datastore 生成的键,请执行以下操作:

  1. 创建 newKeyFactory

  2. 调用 setKind() 方法以确定用于查询分类的实体的 kind

  3. 附加 newKey() 方法以生成 Datastore 键:

    //Prepare a new entity
    String kind = "visit";
    Key key = datastore.allocateId(datastore.newKeyFactory().setKind(kind).newKey());
    

修改实体创建

获取 Datastore 键后,使用以下方法创建实体:

  1. 使用 Entity.newBuilder 并传递 Datastore 生成的键

    找到使用 Entity 构造函数调用的行,如以下所示:

    Entity visit = new Entity(kind);
    

    Entity 构造函数调用替换为 Entity.newBuilder 构造函数调用,如以下所示:

    Entity visit = Entity.newBuilder(key);
    
  2. 使用 set 方法设置实体的属性。

    第一个参数是预期属性,第二个参数是值。 对于 timestamp 属性,该值为 Timestamp,而不是 Instant.toString()

    找到使用 setProperty 方法的行,如以下所示:

    visit.setProperty("user_ip", userIp);
    visit.setProperty("timestamp", Instant.now().toString());
    

    setProperty 方法替换为 set 方法,如以下所示:

    Entity visit = Entity.newBuilder(key).set("user_ip", userIp).set("timestamp", Timestamp.now()).build();
    

提交事务

Datastore 模式 Firestore 客户端库使用 add() 方法来提交事务。如需提交事务,请运行以下命令:

  1. 查找使用 put() 方法的行,如以下所示:

    // Save the entity
    datastore.put(visit);
    
  2. put() 方法替换为 add() 方法,如以下所示:

    // Save the entity
    datastore.add(visit);
    

查询结果

查询会检索满足一组指定条件的 entities。您可以使用以下方法显示结果:

  • OrderBy 方法按升序或降序显示结果。

  • Limit 方法限制在同一构建器中使用的提取结果数上限。

查询使用带有 kind 变量的构建器模式方法。在获取 Datastore 生成的键步骤中,kind 变量设置为 Visit

如需检索前 10 个结果,请执行以下操作:

  1. 查找使用 addSort() 方法的行,如以下所示:

      // Retrieve the last 10 visits from the datastore, ordered by timestamp.
      Query query = new Query(kind).addSort("timestamp", Query.SortDirection.DESCENDING);
      List<Entity> results = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(10));
    
  2. addSort() 方法替换为 setOrderBy() 方法,并附加 setLimit() 方法,如以下所示:

    // Retrieve the last 10 visits from the datastore, ordered by timestamp.
    Query<Entity> query = Query.newEntityQueryBuilder()
                            .setKind(kind)
                            .setOrderBy(StructuredQuery.OrderBy.desc("timestamp"))
                            .setLimit(10)
                            .build();
    
  3. 查询准备就绪后,使用 datastore.run() 执行该代码,然后将结果收集到 QueryResultsEntity 集合中。

    生成的 QueryResults 对象是具有 hasNext() 函数的迭代器。

  4. 检查结果集是否有要处理的 next 对象,而不是循环遍历结果列表。例如:

    QueryResults<Entity> results = datastore.run(query);
    
          resp.setContentType("text/plain");
          PrintWriter out = resp.getWriter();
          out.print("Last 10 visits:\n");
          while (results.hasNext()) {
              Entity entity = results.next();
              out.format(
                      "Time: %s Addr: %s\n", entity.getTimestamp("timestamp"), entity.getString("user_ip"));
          }
    

示例

如需查看将 Java 8 应用迁移到 Datastore 模式 Firestore 的示例,请比较 Java 8 版 App Engine Datastore 代码示例Datastore 模式 Firestore 代码示例

后续步骤