開始使用:Cloud Datastore

瞭解如何建立將資料儲存於 Google Cloud Datastore (非關聯 (NoSQL) 資料庫) 的 App Engine 應用程式。

Cloud Datastore 為 App Engine 適用的儲存空間選項,能與應用程式輕鬆整合及儲存文字資料。比較 Cloud Datastore、Cloud SQL 及 Cloud Storage,選擇符合您應用程式需求的儲存空間。

此範例參考了一系列指南,示範如何在 Cloud Datastore 中儲存網誌文章資料。

事前準備

設定開發環境並建立 App Engine 專案

匯入程式庫

此範例使用下列程式庫:

import com.google.appengine.api.datastore.DatastoreFailureException;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Query.FilterPredicate;

import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;

您在自己工作中所使用的程式庫可能會有所不同,視您使用的資料儲存庫功能而定。並非所有工作都需要列出所有程式庫,只匯入需要的程式庫是不錯的做法。

設定 Cloud Datastore 連線

讀取或寫入 Cloud Datastore 之前,您必須先建立 DatastoreService 物件,並使用此物件與 Cloud Datastore 通訊。使用下列程式碼建立連線:

DatastoreService datastore;
datastore = DatastoreServiceFactory.getDatastoreService();

DatastoreService 為重型物件,所以請務必使用批次作業,將呼叫數減至最低。

建立及儲存實體

物件會在 Cloud Datastore 中儲存為實體,物件資料則以實體屬性儲存。此範例會以名為 post 的實體儲存資料,此實體有四個屬性:titlebodyauthortimestamp

資料會透過 HTML 表單提交,如處理使用者提交的表單資料所述。

DatastoreService datastore;

@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException {

  // Create a map of the httpParameters that we want and run it through jSoup
  Map<String, String> blogContent =
      req.getParameterMap()
          .entrySet()
          .stream()
          .filter(a -> a.getKey().startsWith("blogContent_"))
          .collect(
              Collectors.toMap(
                  p -> p.getKey(), p -> Jsoup.clean(p.getValue()[0], Whitelist.basic())));

  Entity post = new Entity("Blogpost"); // create a new entity

  post.setProperty("title", blogContent.get("blogContent_title"));
  post.setProperty("author", blogContent.get("blogContent_author"));
  post.setProperty("body", blogContent.get("blogContent_description"));
  post.setProperty("timestamp", new Date().getTime());

  try {
    datastore.put(post); // store the entity

    // Send the user to the confirmation page with personalised confirmation text
    String confirmation = "Post with title " + blogContent.get("blogContent_title") + " created.";

    req.setAttribute("confirmation", confirmation);
    req.getRequestDispatcher("/confirm.jsp").forward(req, resp);
  } catch (DatastoreFailureException e) {
    throw new ServletException("Datastore error", e);
  }
}

@Override
public void init() throws ServletException {

  // setup datastore service
  datastore = DatastoreServiceFactory.getDatastoreService();
}

在範例中,每個 post 實體都具備由 Cloud Datastore 自動建立的 ID。如要改為指派自己的 ID,請在建立實體時進行指定:

Entity post = new Entity("Blogpost", "[IDENTIFIER]");

當您要更新更新實體所述的現有實體時,指定 ID 的功能非常重要。

建立 post 實體後,請使用 setProperty() 來設定 titleauthorbodytimestamp 屬性,然後使用 put,在 Cloud Datastore 中儲存含有完整屬性值的實體。

datastore.put(post);

讀取實體

如要從 Cloud Datastore 讀取實體,您必須使用查詢。範例使用的查詢會在頭版顯示五篇網誌文章:

final Query q =
    new Query("Blogpost").setFilter(new FilterPredicate("title", FilterOperator.NOT_EQUAL, ""));

PreparedQuery pq = datastore.prepare(q);
List<Entity> posts = pq.asList(FetchOptions.Builder.withLimit(5)); // Retrieve up to five posts

posts.forEach(
    (result) -> {
      // Grab the key and convert it into a string in preparation for encoding
      String keyString = KeyFactory.keyToString(result.getKey());

      // Encode the entity's key with Base64
      String encodedID = new String(Base64.getUrlEncoder().encodeToString(String.valueOf(keyString).getBytes()));

      // Build up string with values from the Datastore entity
      String recordOutput =
          String.format(blogPostDisplayFormat, result.getProperty("title"), result.getProperty("timestamp"),
              result.getProperty("author"), encodedID, encodedID, result.getProperty("body"));

      out.println(recordOutput); // Print out HTML
    });

Cloud Datastore query 物件支援使用 setFilter (與 SQL WHERE 子句類似) 進行篩選。此範例使用 FetchOptions.Builder 類別來擷取五篇網誌文章。

如要查看使用游標分批顯示不限數量項目的範例,請參閱 Bookshelf 教學課程

更新實體

如要更新實體,請使用與原始實體相同的金鑰來建立新的實體。此範例會建立具有與原始實體相同之金鑰的新 post 實體,但在儲存新實體前,此範例會在該實體的屬性中填入更新的文字。

// Decode the websafe ID
String decodedKey = new String(Base64.getUrlDecoder().decode(blogContent.get("blogContent_id")));

// Create a key from the decoded websafe string
Key originalPostKey = KeyFactory.stringToKey(decodedKey);

// Create a new entity with the same key as the original
Entity post = new Entity("Blogpost", originalPostKey.getId());

// Populate the new entity with the updated blog post contents
post.setProperty("title", blogContent.get("blogContent_title"));
post.setProperty("author", blogContent.get("blogContent_author"));
post.setProperty("body", blogContent.get("blogContent_body"));
post.setProperty("timestamp", new Date());

try {
  datastore.put(post); // Store the post

  // Send the user to the confirmation page with personalised confirmation text
  String confirmation = "Post with title " + blogContent.get("blogContent_title") + " updated.";

  req.setAttribute("confirmation", confirmation);
  req.getRequestDispatcher("/confirm.jsp").forward(req, resp);
} catch (DatastoreFailureException e) {
  throw new ServletException("Datastore error", e);
}

刪除實體

如要在 Cloud Datastore 中刪除實體,請呼叫 delete 方法以傳送待刪除之文章的 Key

// Get the websafe cursor and then convert it into a usable key
// for retrieving a particular post
Map<String, String[]> blogContent = req.getParameterMap();
String[] postId = blogContent.get("id");
String decodedKey = new String(Base64.getUrlDecoder().decode(postId[0])); // Decode the websafe ID

try {
  try {
    Entity deletePost = datastore.get(KeyFactory.stringToKey(decodedKey));
    // Delete the entity based on its key
    datastore.delete(deletePost.getKey());

    // Send the user to the confirmation page with personalised confirmation text
    String confirmation = "Post " + deletePost.getProperty("title") + " has been deleted.";

    req.setAttribute("confirmation", confirmation);
    req.getRequestDispatcher("/confirm.jsp").forward(req, resp);

  } catch (EntityNotFoundException e) {
    throw new ServletException("Datastore error", e);
  }
} catch (DatastoreFailureException e) {
  throw new ServletException("Datastore error", e);
}

此範例中已編碼的原始金鑰 ID 會透過網址傳送至範例應用程式,在範例應用程式中解碼,並在從 KeyFactory 類別呼叫 createKey 時做為金鑰值。 createKey 需要實體類型 Blogpost 與 ID,此 ID 可從 Servlet 要求變數中擷取並轉換成 Long 整數。

部署至 App Engine

您可以透過 Maven 將應用程式部署至 App Engine。

請前往專案的根目錄,並輸入以下內容:

mvn appengine:deploy

請在 Maven 部署應用程式後輸入下列指令,以便在新的應用程式中自動開啟網路瀏覽器分頁:

gcloud app browse

後續步驟

Cloud Datastore 很適合用來儲存文字資料;如要儲存圖片,我們建議您使用 Cloud Storage。

使用 Cloud Storage

本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Java 適用的 App Engine 標準環境