Google 数据协议中的批处理

借助批处理,您可以在一个请求中执行多项操作,而不必单独提交每项操作。

注意:要执行批量操作,您需要使用最新版本的 Google 数据 API 客户端库。JavaScript 客户端库不支持批量操作。

观众

本文适用于希望通过批处理在单个请求中提交多个操作的程序员。

本文档假定您熟悉 GData Java 客户端库。本文档中的示例展示了如何使用 Java 客户端库运行批量操作。

本文档中的示例仅适用于 Google Base Data API。不过,其他服务也可能提供批量功能。

注意:其他客户端库的协议和常规过程将相同,但执行批量请求的具体方法可能会有所不同。请参阅特定于客户端库的文档。

简介

使用 GData 批量 Feed,您可以收集多个插入、更新、删除和查询操作,然后一次性提交和执行所有这些操作。

例如,以下 Feed 包含四个操作:

<feed>
  <entry>
    <batch:operation type="insert"/>
    ... what to insert ...
  </entry> 
  <entry>
    <batch:operation type="update"/>
    ... what to update ...
  </entry>
  <entry>
    <batch:operation type="delete"/>
    ... what to delete ...
  </entry>
  <entry>
    <batch:operation type="query"/>
    ... what to query ...
  </entry>
</feed>

该服务将执行尽可能多的请求更改,并返回状态信息,您可以利用该信息评估每项操作的成功或失败情况。

该服务会尝试执行批次中的每项操作,即使该批次中包含的一些操作没有成功也是如此。

提交批量请求

批量请求应以 HTTP POST 的形式发送到批量网址。不同的 Feed 支持不同的批量操作。只读 Feed 仅支持查询。

若要了解指定 Feed 是否支持批量操作,您可以查询 Feed。如果 Feed 在 Feed 级别包含“批量”链接关系,则表示 Feed 支持批量操作。

“批量”链接关系是包含 rel="http://schemas.google.com/g/2005#batch"<link> 元素。关联关系的 href 属性定义了批量操作的 Feed 文档的网址。

例如,如果您执行 GET http://www.google.com/base/feeds/items(常规 Google Base“商品”Feed),则可能会收到以下响应:

<feed xmlns=...
  <id>http://www.google.com/base/feeds/items</id>
  <link rel="http://schemas.google.com/g/2005#feed"
    type="application/atom+xml"
    href="http://www.google.com/base/feeds/items"/>
  <link rel="http://schemas.google.com/g/2005#post"
    type="application/atom+xml"
    href="http://www.google.com/base/feeds/items"/>
  <link rel="http://schemas.google.com/g/2005#batch"
    type="application/atom+xml"
    href="http://www.google.com/base/feeds/items/batch"/>
  ...
</feed> 

在此示例中,批量网址为 http://www.google.com/base/feeds/items/batch

编写批量操作 Feed

操作 Feed 包含用于插入、更新、删除或查询的条目列表。每个操作都由 <batch:operation type="insert|update|delete|query"/> 元素定义。

此元素可以是 <feed> 元素的直接子项,也可以是 Feed 中任何条目的直接子项,也可以同时是两者的子项。它包含在某条目中时,可指定要对该特定条目执行的操作。添加到 Feed 中时,此元素会指定在没有 <batch:operation/> 元素的任何条目上执行的默认操作。

当条目和 Feed 均未指定操作时,默认操作为 insert

应用不应将多个操作应用于单个批量 Feed 中的同一条目。如果您为同一条目指定多项操作,则结果无法确定。

为了提高性能,可能无法按请求的顺序处理操作。但是,最终结果始终与条目已按顺序处理一样。

您发送到服务器的 XML 的字节数不得超过 1 MB(1048576 字节)。一般来说,只要总字节大小不超过 1 MB,您可以请求的操作数量就没有限制。不过,某些服务可能会施加其他限制。

如需使用批量操作,您必须将批量命名空间声明作为属性添加到 <feed> 元素中:

<feed 
  xmlns="http://www.w3.org/2005/Atom"
  xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/"
  ...
  xmlns:batch="http://schemas.google.com/gdata/batch">

插入操作

插入操作表示如下:

<batch:operation type="insert">

插入操作相当于 POST 条目。操作成功后,系统会返回整个条目内容,其中包含更新后的文档 <id> 元素和 <batch:status code="201"/> 元素。

以下是成功插入请求的示例:

<entry>
  <title type="text">...</title>
  <content type="html">...</content>
  <batch:id>itemA</batch:id>
  <batch:operation type="insert"/>
  <g:item_type>recipes</g:item_type>
  ... 
</entry>

以下是成功插入请求的响应示例:

<entry>
  <batch:status code="201"/>
  <batch:id>itemA</batch:id>
  <batch:operation type="insert"/>
  <id>http://www.google.com/base/feeds/items/17437536661927313949</id>
  <link rel="self" type="application/atom+xml"
    href="http://www.google.com/base/feeds/items/17437536661927313949"/>
  <title type="text">...</title>
  <content type="html">...</content>
  <g:item_type>recipes</g:item_type>
  ... 
</entry>

更新操作

<batch:operation type="update">

更新操作等同于对条目的 <id> 元素引用的网址执行 PUT。操作成功后,系统会返回包含 <batch:status code="200"/> 元素的整个条目内容。

注意:对于某些 Feed,您还需要通过批量更新请求指定条目的 rel="edit" 链接。这包括支持 Google 数据协议 v1 样式的乐观并发的 Feed,以及没有 ID 是网址的 ID 的 Feed。

以下是更新请求的示例:

<entry>
  <id>http://www.google.com/base/feeds/items/17437536661927313949</id>
  <batch:operation type="update"/>
  ...
</entry>

以下是成功响应的示例:

<entry>
  <batch:status code="200"/>
  <id>http://www.google.com/base/feeds/items/17437536661927313949</id>
  <batch:operation type="update"/>
  ... 
</entry>

注意:某些 Feed 使用强大的 ETag 来防止您不小心修改他人的更改。针对其中一个 Feed 中的条目发出批量更新请求时,您必须在该条目的 gd:etag 属性中提供 ETag 值。例如:<entry gd:etag="'F08NQAxFdip7IWA6WhVR'">...<batch:operation type="update"/>...

部分更新操作

对于支持部分更新的 Feed,您还可以在批量请求中使用此类更新。部分更新操作等同于对条目的 <id> 元素引用的网址执行 PATCH。操作成功后,系统会返回包含 <batch:status code="200"/> 元素的整个条目内容。

注意:对于某些 Feed,您还需要通过批量更新请求指定条目的 rel="edit" 链接。这包括支持 Google 数据协议 v1 样式的乐观并发的 Feed,以及没有 ID 是网址的 ID 的 Feed。

<batch:operation type="patch"/>

以下是部分更新请求的示例:

<entry gd:fields="content" gd:etag="FE8LQQJJeSp7IWA6WhVa">
  <id>http://www.google.com/calendar/feeds/jo@gmail.com/private/full/entryID</id>
  <batch:operation type="patch"/>
  <title>New title</title>
</entry>

以下是一个成功响应的示例:

<entry gd:etag="FE8LQQJJeSp7IWA6WhVa">
  <batch:status code="200"/>
  <id>http://www.google.com/calendar/feeds/jo@gmail.com/private/full/entryID</id>
  <batch:operation type="patch"/>
  <title>New title</title>
  <content></content>
  ...rest of the entry...
</entry>

删除操作

<batch:operation type="delete">

删除操作等同于对条目的 <id> 元素引用的网址执行 DELETE。对于删除操作,您只需发送 <id> 元素即可删除该条目。您在 batch: 命名空间之外的元素中提供的任何其他信息将被忽略。操作成功后,系统将返回具有相同 ID 的条目,其中包含 <batch:status code="200"/> 元素。

注意:对于某些 Feed,您还需要使用批量删除请求指定条目的 rel="edit" 链接。这包括支持 Google 数据协议 v1 样式的乐观并发的 Feed,以及没有 ID 是网址的 ID 的 Feed。

以下是删除请求的示例:

<entry>
  <batch:operation type="delete"/>
  <id>http://www.google.com/base/feeds/items/17437536661927313949</id>
</entry>

以下是成功响应的示例:

<entry>
  <batch:operation type="delete"/>
  <id>http://www.google.com/base/feeds/items/17437536661927313949</id>
  <batch:status code="200" reason="Success"/>
</entry>

注意:某些 Feed 使用强大的 ETag 来防止您不小心修改他人的更改。针对某个 Feed 中的条目发出批量删除请求时,您必须在该条目的 gd:etag 属性中提供 ETag 值。例如:<entry gd:etag="'F08NQAxFdip7IWA6WhVR'">...<batch:operation type="delete"/>...

查询操作

<batch:operation type="query">

查询操作相当于对条目的 <id> 元素引用的网址执行 GET。操作成功后,返回整个条目内容。

注意:对于某些 Feed,您还需要通过批量查询请求指定条目的 rel="self" 链接。其中包括那些没有 ID 为网址的 Feed。

以下是查询请求的示例:

<entry>
  <id>http://www.google.com/base/feeds/items/1743753666192313949</id>
  <batch:operation type="query"/>
</entry>

以下是成功响应的示例:

<entry>
  <id>http://www.google.com/base/feeds/items/1743753666192313949</id>
  <batch:operation type="query"/>
  <batch:status code="200" reason="Success"/>
   ...
</entry>

跟踪操作

GData 条目结果的返回顺序不一定与请求相同。您可以使用标识符来跟踪操作的整个生命周期。

对于更新、删除和查询操作,您可以使用条目本身的 ID 来跟踪操作。

对于插入操作,由于尚无 ID,因此您可以传入操作标识符。此标识符可用于将结果条目与请求条目相关联。操作标识符在 <batch:id> 元素中传递。

对于每个操作,GData 都会返回一个响应,说明操作是成功还是失败。每个响应均标识相关条目。对于更新、删除或查询操作,或者成功的插入操作,将始终返回条目 ID。如果您已指定批次 ID,则系统也会返回此 ID。由于插入操作不成功,因此没有关联的条目 ID,因此只会返回批次 ID。

使用每个操作的标识符,您可以仅重试失败的操作,而不必重新提交整个批次的操作。

<batch:id> 的内容是客户端定义的字符串值,将在相应的响应条目中回显。您可以指定任何有助于客户端将响应与原始请求中的条目相关联的值。即使操作失败,此元素也将在相应条目中回显。GData 绝不会存储或解释该批次 ID 的内容。

以下示例展示了批量操作 Feed。请注意,<batch:id> 元素将此操作标记为 itemB

<entry>
  <title type="text">...</title>
  <content type="html">...</content>
  <batch:id>itemB</batch:id>
  <batch:operation type="insert"/>
  <g:item_type>recipes</g:item_type>
</entry>

以下示例是为响应此操作而返回的批量状态条目。

<entry>
  <id>http://www.google.com/base/feeds/items/2173859253842813008</id>
  <published>2006-07-11T14:51:43.560Z</published>
  <updated>2006-07-11T14:51: 43.560Z</updated>
  <title type="text">...</title>
  <content type="html">...</content>
  <link rel="self" 
    type="application/atom+xml" 
    href="http://www.google.com/base/feeds/items/2173859253842813008"/>
  <link rel="edit" 
    type="application/atom+xml" 
    href="http://www.google.com/base/feeds/items/2173859253842813008"/>
  <g:item_type>recipes</g:item_type>
  <batch:operation type="insert"/>
  <batch:id>itemB</batch:id>
  <batch:status code="201" reason="Created"/>
</entry>

处理状态代码

状态代码由以下元素表示:

<batch:status code="200|201|404|500|..." reason="reason" [content-type="type"]/>

响应 Feed 中的每个条目都包含一个 <batch:status> 元素。此元素描述执行操作时出现的情况。它模拟的是相应操作是单独发送,而不是作为批量 Feed 的一部分发送的 HTTP 响应。

您需要检查响应中每个条目的 <batch:status> 元素,以了解关联的操作是否已成功处理。code="n" 属性包含 GData 状态代码

状态说明

<batch:status> 元素的 reason="reason" 属性包含对操作状态的更详细解释。

内容类型

<batch:status> 元素的 content-type="type" 属性包含 <batch:status> 元素中所含数据的 MIME 类型。对应于 HTTP 状态响应的 Content-Type 标头。该属性是可选属性。

设置内容类型后,<batch:status> 元素的正文会说明在处理条目时遇到的问题。

识别中断的操作

中断操作的响应中包含以下元素:

<batch:interrupted reason="reason" success="N" failures="N" parsed="N">

此元素表示批处理中断,并且尝试恢复中断原因的所有操作均失败。某些条目可能已成功处理。系统会放弃在该时间点之前未报告为成功的所有条目。

此元素非常不同,通常表示在请求正文中发送的 Feed 的 XML 格式有误。

<batch:status> 元素一样,您可以在 reason 属性中找到短状态代码。元素内也可能会显示更长的响应。

批量操作 Feed 和状态 Feed 示例

以下是可发送到服务器的批量操作 Feed。此 Feed 请求服务器删除两个条目并添加两个新条目。请注意, <feed> 元素必须包含用于批处理的命名空间增量,如以下示例所示。

POST : http://www.google.com/base/feeds/items/batch
<?xml version="1.0" encoding="UTF-8"?>
<feed
  xmlns="http://www.w3.org/2005/Atom"
  xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/"
  xmlns:g="http://base.google.com/ns/1.0"
  xmlns:batch="http://schemas.google.com/gdata/batch">
  <title type="text">My Batch Feed</title>
  <entry>
    <id>http://www.google.com/base/feeds/items/13308004346459454600</id>
    <batch:operation type="delete"/>
  </entry>
  <entry>
    <id>http://www.google.com/base/feeds/items/17437536661927313949</id>
    <batch:operation type="delete"/>
  </entry>
  <entry>
    <title type="text">...</title>
    <content type="html">...</content>
    <batch:id>itemA</batch:id>
    <batch:operation type="insert"/>
    <g:item_type>recipes</g:item_type>
  </entry>
  <entry>
    <title type="text">...</title>
    <content type="html">...</content>
    <batch:id>itemB</batch:id>
    <batch:operation type="insert"/>
    <g:item_type>recipes</g:item_type>
  </entry>
</feed>

我们假设两个插入都有效,但其中两个删除失败。在这种情况下,批量状态 Feed 可能会如下所示。 请注意,这些条目与批量操作 Feed 相比已经过重新排序。

<?xml version="1.0" encoding="UTF-8"?>
<feed
  xmlns="http://www.w3.org/2005/Atom"
  xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/"
  xmlns:g="http://base.google.com/ns/1.0"
  xmlns:batch="http://schemas.google.com/gdata/batch">
  <id>http://www.google.com/base/feeds/items</id>
  <updated>2006-07-11T14:51:42.894Z</updated>
  <title type="text">My Batch</title>
  <link rel="http://schemas.google.com/g/2005#feed"
    type="application/atom+xml"
    href="http://www.google.com/base/feeds/items"/>
  <link rel="http://schemas.google.com/g/2005#post"
    type="application/atom+xml"
    href="http://www.google.com/base/feeds/items"/>
  <link rel=" http://schemas.google.com/g/2005#batch"
    type="application/atom+xml"
    href="http://www.google.com/base/feeds/items/batch"/>
  <entry>
    <id>http://www.google.com/base/feeds/items/2173859253842813008</id>
    <published>2006-07-11T14:51:43.560Z</published>
    <updated>2006-07-11T14:51: 43.560Z</updated>
    <title type="text">...</title>
    <content type="html">...</content>
    <link rel="self"
      type="application/atom+xml"
      href="http://www.google.com/base/feeds/items/2173859253842813008"/>
    <link rel="edit"
      type="application/atom+xml"
      href="http://www.google.com/base/feeds/items/2173859253842813008"/>
    <g:item_type>recipes</g:item_type>
    <batch:operation type="insert"/>
    <batch:id>itemB</batch:id>
    <batch:status code="201" reason="Created"/>
  </entry>
  <entry>
    <id>http://www.google.com/base/feeds/items/11974645606383737963</id>
    <published>2006-07-11T14:51:43.247Z</published>
    <updated>2006-07-11T14:51: 43.247Z</updated>
    <title type="text">...</title>
    <content type="html">...</content>
    <link rel="self"
      type="application/atom+xml"
      href="http://www.google.com/base/feeds/items/11974645606383737963"/>
    <link rel="edit"
      type="application/atom+xml"
      href="http://www.google.com/base/feeds/items/11974645606383737963"/>
    <g:item_type>recipes</g:item_type>
    <batch:operation type="insert"/>
    <batch:id>itemA</batch:id>
    <batch:status code="201" reason="Created"/>
  </entry>
  <entry>
    <id>http://www.google.com/base/feeds/items/13308004346459454600</id>
    <updated>2006-07-11T14:51:42.894Z</updated>
    <title type="text">Error</title>
    <content type="text">Bad request</content>
    <batch:status code="404"
      reason="Bad request"
      content-type="application/xml">
      <errors>
        <error type="request" reason="Cannot find item"/>
      </errors>
    </batch:status>
  </entry>
  <entry>
    <id>http://www.google.com/base/feeds/items/17437536661927313949</id>
    <updated>2006-07-11T14:51:43.246Z</updated>
    <content type="text">Deleted</content>
    <batch:operation type="delete"/>
    <batch:status code="200" reason="Success"/>
  </entry>
</feed>

使用 GData Java 客户端库的批处理功能

本部分介绍如何使用 GData Java 客户端库的批处理功能提交一组插入、更新和/或删除请求。

本部分提供的示例使用 Google Base API。

除了标准 GData 和 Google Base 类之外,首先还要导入您需要的类:

import com.google.gdata.data.batch.*;
import com.google.api.gbase.client.*;

要提交批量请求,您需要从 Feed 中获取批量网址。以下代码段说明了如何执行此操作,并假设 feed 是包含 Feed 相关信息的 GoogleBaseFeed 对象:

Link batchLink = feed.getLink(Link.Rel.FEED_BATCH, Link.Type.ATOM);
if (batchLink != null) {
  URL batchUrl = new URL(batchLink.getHref());
  ... // batch handling
} else {
  // batching is not supported for this feed
}

以下代码段准备了一个 Feed,该 Feed 会在一次操作中插入两个条目:

GoogleBaseEntry entry1 = new GoogleBaseEntry();
...   // initialize entry 1 content
BatchUtils.setBatchId(entry1, "A"); // A is the local batch ID for this entry
feed.addEntry(entry1);
GoogleBaseEntry entry2 = new GoogleBaseEntry();
... // initialize entry 2 content
BatchUtils.setBatchId(entry2, "B"); // B is the local batch ID for this entry
feed.addEntry(entry2);

此示例中的代码从未明确指出要为这些条目执行的操作是 insert。插入操作是默认操作,因此您无需明确指定。

如需发送批量 Feed 并接收结果,请调用 Service.batch 方法。

Service.insert 一样,Service.batch 会返回设置了新 <atom:id> 值的插入条目。返回的条目包含在 GoogleBaseFeed 对象中。

如果要在插入其他两个条目的同时删除第三个条目(已提取并存储在 entry3 中),可以使用以下代码:

GoogleBaseEntry toDelete = new GoogleBaseEntry();


toDelete.setId(entry3.getId());
BatchUtils.setBatchOperationType(toDelete, BatchOperationType.DELETE);

feed.addEntry(toDelete);


GoogleBaseFeed result = service.batch(batchUrl, feed);

此处,servicecom.google.gdata.client.Service 的实例。

如果要更新条目,请指定 OperationType.UPDATE,并使用所需的更改初始化条目,而不是将其主要留空。

这些示例使用 Google Base 数据 API。如果您将 service.batch 与其他类型的 GData 服务搭配使用,请将 GoogleBaseFeedGoogleBaseEntryGoogleBaseService 类替换为相应的 Feed、条目和服务类。

批量操作的结果不一定会按照请求的顺序返回。在上面的示例中,结果 Feed 很可能包含 entry2 后跟 entry1。您绝不应假设系统以任何特定顺序返回条目。

您的批量操作 Feed 应该为每个插入操作分配一个唯一的批量操作 ID,具体说明请参阅跟踪操作。在上面的示例中,批量 ID 为 AB。因此,要查找所请求的操作的状态,您应遍历返回的批量 Feed 中的条目并比较其批次 ID 或条目 ID,如下所示:

for (GoogleBaseEntry entry : result.getEntries()) {
  String batchId = BatchUtils.getBatchId(entry);      
  if (BatchUtils.isSuccess(entry)) {     
    if ("A".equals(batchId)) {       
      entry1 = entry;     } 
    else if ("B".equals(batchId)) {       
      entry2 = entry;     } 
    else if (BatchUtils.getBatchOperationType(entry) 
      == BatchOperationType.DELETE) {       
      System.out.println("Entry " + entry.getId() +
      " has been deleted successfully.");     
    }      
  } else {     
    BatchStatus status = BatchUtils.getBatchStatus(entry);     
    System.err.println(batchId + " failed (" +                
      status.getReason() + ") " +  status.getContent());      
    }    
  } 

您将在返回的 Feed 中找到的每个条目都有一个关联的 BatchStatus 对象。BatchStatus 对象包含一个 HTTP 返回代码以及一个响应,该响应描述了处理条目时发生的问题。您需要检查每个条目的 HTTP 返回代码,以判断操作是否成功。

在上面的示例中,检查是由便捷方法 BatchUtils.isSuccess 完成的。在此示例中,它相当于 BatchUtils.getBatchStatus(entry) < 300

处理状态代码中进一步介绍了状态代码和响应。

返回页首