高级查询机制
隐式(或自动提交)事务
这是运行 Cypher 查询最基本和最有限的形式。驱动程序不会自动重试隐式事务,而是针对使用 Driver.executeQuery()
和 托管事务 运行的查询执行此操作。仅当其他驱动程序查询接口不适合该目的或用于快速原型设计时,才应使用隐式事务。
您可以使用方法 Session.run()
运行隐式事务,该方法返回一个 Result
对象。
let session = driver.session({database: 'neo4j'})
try {
const result = await session.run(
'MERGE (a:Person {name: $name})',
{ name: 'Alice'}
)
} finally {
await session.close()
}
由于驱动程序无法确定 session.run()
调用中的查询是否需要数据库的读或写会话,因此它默认为写。如果您的隐式事务仅包含读取查询,则可以通过在创建会话时设置关键字参数 defaultAccessMode=neo4j.session.READ
来 使驱动程序感知,从而提高性能。
隐式事务是唯一可以用于 CALL { … } IN TRANSACTIONS 查询的事务。.
|
您也可以使用 反应式会话 运行隐式事务。 |
导入 CSV 文件
使用 Session.run()
最常见的用例是使用 LOAD CSV
Cypher 子句将大型 CSV 文件导入数据库,并防止由于事务大小导致的超时错误。
let session = driver.session({database: 'neo4j'})
try {
let result = await 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
`)
console.log(result.summary.counters.updates())
} finally {
await session.close()
}
虽然 LOAD CSV 可以提供便利,但将 CSV 文件的解析延迟到您的 JavaScript 应用程序并避免 LOAD CSV 并没有什么错误。实际上,将解析逻辑移动到应用程序可以使您更好地控制导入过程。有关高效的批量数据插入,请参阅 性能→批量数据创建。 |
有关更多信息,请参阅 Cypher→子句→加载 CSV。
事务配置
您可以通过向 session.run()
提供一个可选的第三个参数(类型为 TransactionConfig
)来进一步控制隐式事务。该配置允许指定查询超时并向事务附加元数据。有关更多信息,请参阅 事务 - 事务配置。
let session = driver.session({database: 'neo4j'})
let result = await session.run(
'MATCH (a:Person) RETURN count(a) AS people',
{}, // query parameters
{ timeout: 5000, metadata: {'appName': 'peopleTracker'} } // transactionConfig
)
属性键、关系类型和标签中的动态值
通常,您不应该将参数直接连接到查询中,而应使用 查询参数。但是,在某些情况下,您的查询结构会阻止在所有部分中使用参数。实际上,虽然参数可用于文字和表达式以及节点和关系 ID,但它们不能用于以下结构
-
属性键,因此
MATCH (n) WHERE n.$param = 'something'
无效; -
关系类型,因此
MATCH (n)-[:$param]→(m)
无效; -
标签,因此
MATCH (n:$param)
无效。
对于这些查询,您被迫使用字符串连接。为了防止 Cypher 注入,您应该将动态值括在反引号中并自行转义它们。请注意,Cypher 处理 Unicode,因此也要注意 Unicode 文字 \u0060
。
let dangerousLabel = 'Special Person\\u0060'
// convert \u0060 to literal backtick, then escape backticks
let escapedLabel = dangerousLabel.replace(/\\u0060/g, '`').replace(/`/g, '``')
let result = await driver.executeQuery(
'MATCH (p:`' + escapedLabel + '`) RETURN p.name',
{},
{database: 'neo4j'}
)
console.log(`Executed query: ${result.summary.query.text}`)
另一种避免字符串连接的解决方法是使用 APOC 过程 apoc.merge.node
。它支持动态标签和属性键,但仅适用于节点合并。
apoc.merge.node
创建具有动态标签/属性键的节点let propertyKey = 'name'
let label = 'Person'
let result = await driver.executeQuery(
'CALL apoc.merge.node($labels, $properties)',
{labels: [label], properties: {property_key: 'Alice'}},
{database: 'neo4j'}
)
如果您在 Docker 中运行 Neo4j,则在启动容器时需要启用 APOC。请参阅 APOC→安装→Docker。 |
日志记录
创建 Driver
实例时,您可以选择指定其日志记录配置。
默认情况下,日志记录已关闭。要打开它,请在初始化驱动程序时指定 logging
选项。作为值,使用函数 neo4j.logging.console()
,它记录到控制台并采用可选参数 level
。日志记录级别可以是 error
、warn
、info
或 debug
。启用一个级别会自动启用所有较高优先级的级别,其默认值为 info
。
debug
的控制台日志记录的驱动程序neo4j.driver(
URI,
neo4j.auth.basic(USER, PASSWORD),
{ // driver config
logging: neo4j.logging.console('debug')
}
)
1681215847749 INFO Routing driver 0 created for server address localhost:7687
1681215847765 INFO Routing table is stale for database: "neo4j" and access mode: "WRITE": RoutingTable[database=neo4j, expirationTime=0, currentTime=1681215847765, routers=[], readers=[], writers=[]]
1681215847773 DEBUG Connection [0][] created towards localhost:7687(127.0.0.1)
1681215847773 DEBUG Connection [0][] C: HELLO {user_agent: 'neo4j-javascript/5.3.0', ...}
1681215847778 DEBUG Connection [0][] S: SUCCESS {"signature":112,"fields":[{"server":"Neo4j/5.8.0","connection_id":"bolt-1782","hints":{"connection.recv_timeout_seconds":{"low":120,"high":0}}}]}
1681215847778 DEBUG Connection [0][bolt-1782] created for the pool localhost:7687
1681215847778 DEBUG Connection [0][bolt-1782] acquired from the pool localhost:7687
1681215847779 DEBUG Connection [0][bolt-1782] C: ROUTE {"address":"localhost:7687"} [] {"db":"neo4j"}
1681215847781 DEBUG Connection [0][bolt-1782] S: SUCCESS {"signature":112,"fields":[{"rt":{"servers":[{"addresses":["localhost:7687"],"role":"WRITE"},{"addresses":["localhost:7687"],"role":"READ"},{"addresses":["localhost:7687"],"role":"ROUTE"}],"ttl":{"low":300,"high":0},"db":"neo4j"}}]}
您还可以指定自定义日志记录函数,例如将日志记录到文件。在这种情况下,logging
选项期望两个属性
-
level
:error
、warn
、info
或debug
之一。启用一个级别会自动启用所有较高优先级的级别。默认为info
。 -
logger
:当需要记录消息时调用的函数。以level, message
作为输入。
error
的控制台日志记录的驱动程序neo4j.driver(
URI,
neo4j.auth.basic(USER, PASSWORD),
{ // driver config
logging: {
level: 'error',
logger: (level, message) => console.log(level + ' ' + message)
}
}
)
您可以在 API 文档 中找到有关日志记录的更多信息。
词汇表
- LTS
-
长期支持版本是保证支持若干年的版本。Neo4j 4.4 是 LTS,Neo4j 5 也将有一个 LTS 版本。
- Aura
-
Aura 是 Neo4j 的完全托管云服务。它提供免费和付费计划。
- Cypher
-
Cypher 是 Neo4j 的图查询语言,可让您从数据库中检索数据。它类似于 SQL,但用于图。
- APOC
-
Cypher 上的绝佳过程 (APOC) 是一个(许多)函数库,这些函数本身无法轻松地用 Cypher 表示。
- Bolt
-
Bolt 是用于 Neo4j 实例和驱动程序之间交互的协议。它默认侦听端口 7687。
- ACID
-
原子性、一致性、隔离性、持久性 (ACID) 是保证数据库事务可靠处理的属性。符合 ACID 的 DBMS 可确保数据库中的数据在发生故障时保持准确和一致。
- 最终一致性
-
如果数据库保证所有集群成员都将在某个时间点存储数据的最新版本,则该数据库最终一致。
- 因果一致性
-
如果读写查询以相同的顺序由集群的每个成员看到,则数据库因果一致。这比最终一致性更强。
- NULL
-
空标记不是类型,而是值不存在的占位符。有关更多信息,请参阅 Cypher→使用
null
。 - 事务
-
事务是工作单元,可以完全提交或在失败时回滚。例如银行转账:它涉及多个步骤,但它们必须全部成功或被恢复,以避免从一个账户中扣除资金但未添加到另一个账户中。
- 背压
-
背压是反对数据流的力。它确保客户端不会被超出其处理能力的数据所淹没。