

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 在要部署 Gremlin 代码的上下文中对其进行测试
<a name="best-practices-gremlin-console-glv-differences"></a>

Gremlin 为客户端提供了多种向服务器提交查询的方法。这些提交模式的不同之处在于查询的评估方式和交易的行为方式。如果您在一种模式下开发而在另一种模式下部署，则这些差异可能会导致意想不到的结果。

**脚本模式（基于字符串的提交）**  
在脚本模式下，客户端将整个查询作为文本字符串发送到服务器。服务器评估完整的字符串，包括所有*终端步骤*，并将结果流回客户端。以下工具和方法使用脚本模式：
+ [Gremlin 控制台](access-graph-gremlin-console.md) — 使用命令时 `:remote`
+ [Neptune 绘图笔记本](graph-notebooks.md)
+ [带有 AWS SDK 或 AWS CLI 的 HTTP](access-graph-gremlin-rest.md)
+ 通过 TinkerPop 驱动程序提交查询字符串（例如，`client.submit("g.V().count()")`在 Java 中使用）

在脚本模式下，客户端将如下所示的查询作为完整字符串发送到服务器：

```
// Script mode – the entire string, including .next(), is sent to the server
// V('non-existing-id') yields nothing because no vertex with that ID exists
Cluster cluster = Cluster.build().addContactPoint("your-neptune-endpoint")
                         .port(8182).enableSsl(true).create();
Client client = cluster.connect();
client.submit("g.V('existing-id').addV('person').V('non-existing-id').next()");
```

服务器评估完整的查询，包括`.next()`。如果未`.next()`找到任何结果，则服务器会引发`NoSuchElementException`，事务将*回滚*。

**字节码模式（GLV 遍历对象）**  
在字节码模式下，客户端使用 Gremlin 语言变体 (GLV) 在本地构建遍历对象。驱动程序将遍历步骤序列化为字节码并将其发送到服务器。终端步骤（例如`.toList()`或）在*客户端`.next()`*执行，以迭代服务器返回的结果。你可以将字节码模式与 [Java](access-graph-gremlin-java.md)、Pyth [on](access-graph-gremlin-python.md)、[Go [JavaScript](access-graph-gremlin-node-js.md)](access-graph-gremlin-go.md)、[.NET](access-graph-gremlin-dotnet.md) 和其他适用于所用的 Neptune 引擎版本的第三方 TinkerPop-compliant 驱动程序一起使用。

在字节码模式下，相同的查询如下所示：

```
// Bytecode mode – the driver sends the traversal steps as bytecode
// .next() executes on the client to iterate results
Cluster cluster = Cluster.build().addContactPoint("your-neptune-endpoint")
                         .port(8182).enableSsl(true).create();
GraphTraversalSource g = traversal().withRemote(
    DriverRemoteConnection.using(cluster));
g.V("existing-id").addV("person").V("non-existing-id").next();
```

驱动程序仅将遍历步骤 (`g.V().addV().V()`) 作为字节码发送。服务器成功评估遍历，提交事务并返回结果集。然后，客户端`.next()`在本地调用以读取结果集。如果结果集为空，则客户端会引发`NoSuchElementException`，但事务*已在服务器上提交*。

**交易行为差异**  
这些模式之间的关键区别在于终端步骤如何影响交易：
+ **脚本模式**-服务器评估终端步骤。如果像这样的终端步骤因为结果集为空而`.next()`失败，则服务器会将查询视为失败并*回滚*事务。服务器不会在同一次遍历中保留任何突变（例如）。`addV()`
+ **字节码模式** — 客户端评估终端步骤。服务器仅评估遍历步骤，成功提交事务并返回结果。如果客户端随后调用`.next()`空结果集，则结果仅`NoSuchElementException`是客户端错误。事务已经提交，因此服务器会*保留*任何变更。

**终端步骤**  
在 Gremlin 中，[终端步骤](https://tinkerpop.apache.org/docs/current/reference/#terminal-steps)是导致将遍历提交给 Neptune 进行评估的步骤。在字节码模式下，终端步骤会触发驱动程序序列化并发送遍历。在脚本模式下，终端步骤是在服务器上评估的查询字符串的一部分。终端步骤是：
+ `hasNext()`— `true` 如果有结果则返回，`false`否则返回。
+ `next()`— 返回下一个结果。`NoSuchElementException`如果不存在任何结果，则抛出。
+ `next(n)`— 以列表形式返回下一个{{n}}结果。
+ `toList()`— 以列表形式返回所有结果。如果不存在任何结果，则返回一个空列表。
+ `toSet()`— 将所有结果作为一个集合返回。如果不存在任何结果，则返回一个空集。
+ `iterate()`— 迭代所有结果而不返回它们。将其用于不需要返回值的突变。

**注意**  
各个语言 GLV 可能会提供特定于其实现的其他终端步骤。有关详细信息，请参阅特定语言的页面。

如果您在一个上下文中开发和测试代码，则可能会遇到问题。例如，Gremlin 控制台以脚本形式提交查询。如果您将代码部署在不同的上下文中，例如通过使用字节码的 Java 驱动程序进行部署，则代码在生产环境中的行为可能会有所不同。

**重要**  
请务必使用与部署 Gremlin 代码相同的提交模式来测试 Gremlin 代码，以避免意外的事务行为。