进一步的查询机制
隐式(或自动提交)事务
这是运行 Cypher 查询最基本和有限的形式。驱动程序不会自动重试隐式事务,而对于使用 .executableQuery()
和使用 受管事务 运行的查询则会。隐式事务只应在其他驱动程序查询接口不适用或用于快速原型开发时使用。
// import java.util.Map
// import org.neo4j.driver.SessionConfig
try (var session = driver.session(SessionConfig.builder().withDatabase("neo4j").build())) {
session.run("CREATE (a:Person {name: $name})", Map.of("name", "Licia"));
}
隐式事务最迟在会话销毁时提交,或者在同一会话中执行另一个事务之前提交。除此之外,无法明确保证隐式事务在会话生命周期内的确切提交时间。为确保隐式事务提交,您可以在其结果上调用 .consume()
方法。
由于驱动程序无法判断 Session.run()
调用中的查询是需要与数据库进行读会话还是写会话,它默认为写。如果您的隐式事务只包含读查询,则通过在创建会话时使用配置方法 .withRouting(RoutingControl.READ)
使驱动程序了解 会带来性能提升。
隐式事务是唯一可用于 CALL { … } IN TRANSACTIONS 查询的事务。.
|
导入 CSV 文件
使用 Session.run()
最常见的用例是使用 LOAD CSV
Cypher 子句将大型 CSV 文件导入数据库,并防止因事务大小而导致的超时错误。
// import java.util.Map
// import org.neo4j.driver.SessionConfig
try (var session = driver.session(SessionConfig.builder().withDatabase("neo4j").build())) {
var result = session.run("""
LOAD CSV FROM 'https://data.neo4j.com/bands/artists.csv' AS line
CALL {
WITH line
MERGE (:Artist {name: line[1], age: toInteger(line[2])})
} IN TRANSACTIONS OF 2 ROWS
""");
var summary = result.consume();
System.out.println(summary.counters());
}
虽然 LOAD CSV 可能很方便,但将 CSV 文件的解析推迟到您的 Java 应用程序中并避免使用 LOAD CSV 并没有什么“不对”。事实上,将解析逻辑移到应用程序中可以更好地控制导入过程。有关高效批量数据插入,请参见 性能 → 批量数据创建。 |
欲了解更多信息,请参见 Cypher → 子句 → LOAD CSV。
事务配置
您可以通过向 Session.run()
调用提供一个 TransactionConfig
对象作为可选的最后一个参数,来进一步控制隐式事务。配置回调允许指定查询超时并为事务附加元数据。欲了解更多信息,请参见 事务 → 事务配置。
// import java.util.Map
// import java.time.Duration
// import org.neo4j.driver.SessionConfig
// import org.neo4j.driver.TransactionConfig
try (var session = driver.session(SessionConfig.builder().withDatabase("neo4j").build())) {
var result = session.run("CREATE (a:Person {name: $name})", Map.of("name", "John"),
TransactionConfig.builder()
.withTimeout(Duration.ofSeconds(5))
.withMetadata(Map.of("appName", "peopleTracker"))
.build()
);
}
属性键、关系类型和标签中的动态值
通常,您不应将参数直接连接到查询中,而应使用 查询参数。但是,在某些情况下,您的查询结构可能无法在所有部分都使用参数。事实上,尽管参数可用于字面量和表达式以及节点和关系 ID,但它们不能用于以下构造:
-
属性键,因此
MATCH (n) WHERE n.$param = 'something'
是无效的; -
关系类型,因此
MATCH (n)-[:$param]→(m)
是无效的; -
标签,因此
MATCH (n:$param)
是无效的。
对于这些查询,您被迫使用字符串连接。为了防止 Cypher 注入,您应该将动态值用反引号括起来并自行转义。请注意,Cypher 处理 Unicode,因此也要注意 Unicode 字面量 \u0060
。
// import org.neo4j.driver.QueryConfig;
var label = "Person\\u0060n";
// convert \u0060 to literal backtick and then escape backticks
var escapedLabel = label.replace("\\u0060", "`").replace("`", "``");
var result = driver.executableQuery("MATCH (p:`" + escapedLabel + "` {name: $name}) RETURN p.name")
.withParameters(Map.of("name", "Alice"))
.withConfig(QueryConfig.builder().withDatabase("neo4j").build())
.execute();
另一种避免字符串连接的解决方法是使用 APOC 过程,例如 apoc.merge.node
,它支持动态标签和属性键。
apoc.merge.node
创建具有动态标签/属性键的节点。// import org.neo4j.driver.QueryConfig;
String propertyKey = "name";
String label = "Person";
var result = driver.executableQuery("CALL apoc.merge.node($labels, $properties)")
.withParameters(Map.of("labels", List.of(label), "properties", Map.of(propertyKey, "Alice")))
.withConfig(QueryConfig.builder().withDatabase("neo4j").build())
.execute();
如果您在 Docker 中运行 Neo4j,APOC 需要在启动容器时启用。参见 APOC → 安装 → Docker。 |
词汇表
- LTS
-
*长期支持* (Long Term Support) 版本是保证支持数年的版本。Neo4j 4.4 是 LTS 版本,Neo4j 5 也将有一个 LTS 版本。
- Aura
-
Aura 是 Neo4j 的全托管云服务。它提供免费和付费方案。
- Cypher
-
Cypher 是 Neo4j 的图查询语言,可让您从数据库中检索数据。它类似于 SQL,但适用于图。
- APOC
-
Awesome Procedures On Cypher (APOC) 是一个函数库(包含许多函数),这些函数本身无法轻松用 Cypher 表达。
- Bolt
-
Bolt 是 Neo4j 实例和驱动程序之间交互所使用的协议。它默认监听端口 7687。
- ACID
-
原子性 (Atomicity)、一致性 (Consistency)、隔离性 (Isolation)、持久性 (Durability) (ACID) 是保证数据库事务可靠处理的属性。符合 ACID 标准的 DBMS 确保数据库中的数据即使发生故障也能保持准确和一致。
- 最终一致性
-
如果数据库保证所有集群成员*在某个时间点*都会存储最新版本的数据,则该数据库是最终一致的。
- 因果一致性
-
如果集群的每个成员都以相同的顺序看到读写查询,则数据库是因果一致的。这比*最终一致性*更强。
- NULL
-
null 标记不是一种类型,而是表示值缺失的占位符。欲了解更多信息,请参见 Cypher → 使用
null
。 - 事务
-
事务是工作的一个单元,它要么完全*提交*,要么在失败时*回滚*。例如银行转账:它涉及多个步骤,但所有步骤都必须成功或被撤销,以避免资金从一个账户扣除但未添加到另一个账户的情况。
- 背压
-
背压是一种阻碍数据流动的力。它确保客户端不会被超出其处理能力的数据量淹没。
- 事务函数
-
事务函数是由
executeRead
或executeWrite
调用执行的回调。在服务器故障的情况下,驱动程序会自动重新执行该回调。 - 驱动程序
-
一个
Driver
对象包含与 Neo4j 数据库建立连接所需的详细信息。