neo4j-driver-python-skill

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

When to Use

适用场景

  • Writing Python code that connects to Neo4j
  • Setting up driver, sessions, transactions, or async patterns
  • Debugging result handling, serialization, or UNWIND batching
  • Reviewing Neo4j driver usage in Python code
  • 编写连接Neo4j的Python代码
  • 设置驱动、会话、事务或异步模式
  • 调试结果处理、序列化或UNWIND批量处理
  • 审查Python代码中Neo4j驱动的使用

When NOT to Use

不适用场景

  • Writing/optimizing Cypher
    neo4j-cypher-skill
  • Driver version upgrades
    neo4j-migration-skill
  • GraphRAG pipelines (
    neo4j-graphrag
    package) →
    neo4j-graphrag-skill

  • 编写/优化Cypher查询 → 使用
    neo4j-cypher-skill
  • 驱动版本升级 → 使用
    neo4j-migration-skill
  • GraphRAG流水线
    neo4j-graphrag
    包)→ 使用
    neo4j-graphrag-skill

Installation

安装

bash
pip install neo4j                  # package name is `neo4j`, NOT `neo4j-driver` (deprecated since v6)
pip install neo4j-rust-ext         # optional: 3–10× faster serialization, same API
Python >=3.10 required for v6.x.

bash
pip install neo4j                  # 包名称为`neo4j`,而非`neo4j-driver`(自v6起已废弃)
pip install neo4j-rust-ext         # 可选:序列化速度提升3–10倍,API保持一致
v6.x版本要求Python ≥3.10

Environment Variables

环境变量

Load connection config from environment — never hardcode credentials.
python
import os
from dotenv import load_dotenv   # pip install python-dotenv

load_dotenv(".env")   # reads NEO4J_URI / NEO4J_USERNAME / NEO4J_PASSWORD / NEO4J_DATABASE

URI      = os.getenv("NEO4J_URI",      "neo4j://localhost:7687")
USER     = os.getenv("NEO4J_USERNAME", "neo4j")
PASSWORD = os.getenv("NEO4J_PASSWORD", "")
DATABASE = os.getenv("NEO4J_DATABASE", "neo4j")
.env
file format:
NEO4J_URI=neo4j+s://xxx.databases.neo4j.io
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=secret
NEO4J_DATABASE=neo4j
Add
.env
to
.gitignore
. Without
python-dotenv
, use
export
in shell or
os.getenv
directly.

从环境中加载连接配置——切勿硬编码凭证。
python
import os
from dotenv import load_dotenv   # 需安装python-dotenv:pip install python-dotenv

load_dotenv(".env")   # 读取NEO4J_URI / NEO4J_USERNAME / NEO4J_PASSWORD / NEO4J_DATABASE

URI      = os.getenv("NEO4J_URI",      "neo4j://localhost:7687")
USER     = os.getenv("NEO4J_USERNAME", "neo4j")
PASSWORD = os.getenv("NEO4J_PASSWORD", "")
DATABASE = os.getenv("NEO4J_DATABASE", "neo4j")
.env
文件格式:
NEO4J_URI=neo4j+s://xxx.databases.neo4j.io
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=secret
NEO4J_DATABASE=neo4j
.env
添加到
.gitignore
中。如果不使用
python-dotenv
,可在shell中使用
export
命令,或直接使用
os.getenv

Driver Lifecycle

驱动生命周期

Create one Driver per application. Thread-safe, expensive to create. Never create per-request.
python
from neo4j import GraphDatabase

URI  = "neo4j+s://xxx.databases.neo4j.io"   # Aura
AUTH = ("neo4j", "password")
每个应用只创建一个Driver实例。Driver是线程安全的,创建成本较高。切勿为每个请求创建Driver。
python
from neo4j import GraphDatabase

URI  = "neo4j+s://xxx.databases.neo4j.io"   # Aura环境
AUTH = ("neo4j", "password")

Context manager — preferred for scripts

上下文管理器——脚本中首选方式

with GraphDatabase.driver(URI, auth=AUTH) as driver: driver.verify_connectivity() # ... work ...
with GraphDatabase.driver(URI, auth=AUTH) as driver: driver.verify_connectivity() # ... 执行操作 ...

Long-lived singleton (service / web app)

长期存在的单例(服务/Web应用)

driver = GraphDatabase.driver(URI, auth=AUTH) driver.verify_connectivity()
driver = GraphDatabase.driver(URI, auth=AUTH) driver.verify_connectivity()

on shutdown:

关闭时:

driver.close()

URI schemes:

| Scheme | Use |
|---|---|
| `neo4j+s://` | TLS + cluster routing — **Aura default** |
| `neo4j://` | Unencrypted + cluster routing |
| `bolt+s://` | TLS, single instance |
| `bolt://` | Unencrypted, single instance |

Auth options: `("user", "pass")` tuple, `basic_auth()`, `bearer_auth("jwt")`, `kerberos_auth("b64")`.

---
driver.close()

URI协议:

| 协议 | 用途 |
|---|---|
| `neo4j+s://` | TLS加密 + 集群路由 —— **Aura默认协议** |
| `neo4j://` | 未加密 + 集群路由 |
| `bolt+s://` | TLS加密,单实例 |
| `bolt://` | 未加密,单实例 |

认证选项:`("user", "pass")`元组、`basic_auth()`、`bearer_auth("jwt")`、`kerberos_auth("b64")`。

---

Choosing the Right API

选择合适的API

APIUse whenAuto-retryStreaming
driver.execute_query()
Most queries — simple, safe default❌ eager
session.execute_read/write()
Large results / multiple queries in one tx
session.run()
LOAD CSV
,
CALL {} IN TRANSACTIONS
, scripts
AsyncGraphDatabase
asyncio applications

API适用场景自动重试流式处理
driver.execute_query()
大多数查询——简单、安全的默认选项❌ 立即加载
session.execute_read/write()
大结果集 / 单个事务中执行多个查询
session.run()
LOAD CSV
CALL {} IN TRANSACTIONS
、脚本
AsyncGraphDatabase
asyncio应用

execute_query
— Default API

execute_query
—— 默认API

python
from neo4j import GraphDatabase, RoutingControl
python
from neo4j import GraphDatabase, RoutingControl

Tuple unpacking — most common

元组解包——最常用方式

records, summary, keys = driver.execute_query( "MATCH (p:Person {name: $name})-[:KNOWS]->(f) RETURN f.name AS name", name="Alice", routing_=RoutingControl.READ, # route reads to replicas database_="neo4j", # always specify — saves a round-trip ) for record in records: print(record["name"]) print(summary.result_available_after, "ms")
records, summary, keys = driver.execute_query( "MATCH (p:Person {name: $name})-[:KNOWS]->(f) RETURN f.name AS name", name="Alice", routing_=RoutingControl.READ, # 将读请求路由到副本节点 database_="neo4j", # 始终指定——减少一次往返请求 ) for record in records: print(record["name"]) print(summary.result_available_after, "毫秒")

Write — check counters

写入操作——检查计数器

summary = driver.execute_query( "CREATE (p:Person {name: $name, age: $age})", name="Bob", age=30, database_="neo4j", ).summary print(summary.counters.nodes_created)

**Trailing-underscore convention** — config kwargs end with `_` (`database_`, `routing_`, `auth_`, `result_transformer_`, `bookmark_manager_`). No query parameter name may end with `_`; pass those via `parameters_={"key_": val}`.

**Never f-string or format Cypher.** Always `$param` — prevents injection and enables plan caching.

`result_transformer_` — reshape before return:
```python
import neo4j
df      = driver.execute_query("MATCH (p:Person) RETURN p.name, p.age", database_="neo4j",
                                result_transformer_=neo4j.Result.to_df)
record  = driver.execute_query("MATCH (p:Person {name:$n}) RETURN p", n="Alice", database_="neo4j",
                                result_transformer_=neo4j.Result.single)   # raises if 0 or 2+ results
Result.single()
raises
ResultNotSingleError
on zero results (not just 2+). Use
single(strict=False)
for None-on-empty.

summary = driver.execute_query( "CREATE (p:Person {name: $name, age: $age})", name="Bob", age=30, database_="neo4j", ).summary print(summary.counters.nodes_created)

**下划线后缀约定**——配置参数以`_`结尾(`database_`、`routing_`、`auth_`、`result_transformer_`、`bookmark_manager_`)。查询参数名称不得以`_`结尾;如需传递此类参数,请使用`parameters_={"key_": val}`。

**切勿使用f-string或格式化字符串拼接Cypher查询**。始终使用`$param`参数化查询——防止注入攻击并启用查询计划缓存。

`result_transformer_`——返回前重塑结果:
```python
import neo4j
df      = driver.execute_query("MATCH (p:Person) RETURN p.name, p.age", database_="neo4j",
                                result_transformer_=neo4j.Result.to_df)
record  = driver.execute_query("MATCH (p:Person {name:$n}) RETURN p", n="Alice", database_="neo4j",
                                result_transformer_=neo4j.Result.single)   # 结果为0或2+时抛出异常
Result.single()
零结果时会抛出
ResultNotSingleError
(不仅仅是2+结果)。使用
single(strict=False)
可在结果为空时返回None。

Managed Transactions (
execute_read
/
execute_write
)

托管事务(
execute_read
/
execute_write

Use for large results or multiple queries in one transaction.
python
with driver.session(database="neo4j") as session:

    def get_people(tx):
        result = tx.run("MATCH (p:Person) WHERE p.name STARTS WITH $pfx RETURN p.name AS name",
                        pfx="Al")
        return [r["name"] for r in result]   # consume INSIDE callback — Result invalid after tx closes

    names = session.execute_read(get_people)

    def create_person(tx):
        tx.run("CREATE (p:Person {name: $name})", name="Carol")

    session.execute_write(create_person)
Result lifetime
Result
is a lazy cursor backed by the open transaction. Returning it unconsumed raises
ResultConsumedError
. Always collect to
list
inside the callback.
Callback may retry on transient failures — keep callbacks idempotent; move side effects (HTTP calls, emails) outside the callback.
Timeout/metadata via
@unit_of_work
(named functions only — cannot decorate lambdas):
python
from neo4j import unit_of_work

@unit_of_work(timeout=5.0, metadata={"app": "svc", "user": user_id})
def get_people(tx):
    return [r["name"] for r in tx.run("MATCH (p:Person) RETURN p.name AS name")]

session.execute_read(get_people)

适用于大结果集或单个事务中执行多个查询的场景。
python
with driver.session(database="neo4j") as session:

    def get_people(tx):
        result = tx.run("MATCH (p:Person) WHERE p.name STARTS WITH $pfx RETURN p.name AS name",
                        pfx="Al")
        return [r["name"] for r in result]   # 在回调内部消费结果——事务关闭后Result失效

    names = session.execute_read(get_people)

    def create_person(tx):
        tx.run("CREATE (p:Person {name: $name})", name="Carol")

    session.execute_write(create_person)
Result生命周期——
Result
是基于打开事务的惰性游标。未消费就返回会抛出
ResultConsumedError
。请始终在回调内部将结果收集为
list
回调可能会重试——针对临时故障,回调函数需保持幂等;将副作用(HTTP调用、邮件发送等)移到回调外部。
通过
@unit_of_work
设置超时/元数据(仅支持命名函数——无法装饰lambda):
python
from neo4j import unit_of_work

@unit_of_work(timeout=5.0, metadata={"app": "svc", "user": user_id})
def get_people(tx):
    return [r["name"] for r in tx.run("MATCH (p:Person) RETURN p.name AS name")]

session.execute_read(get_people)

Implicit Transactions (
session.run
)

隐式事务(
session.run

Not auto-retried. Use only for
LOAD CSV
,
CALL {} IN TRANSACTIONS
, or quick scripts.
python
with driver.session(database="neo4j") as session:
    result = session.run("CREATE (p:Person {name: $name})", name="Alice")
    summary = result.consume()   # call consume() to guarantee commit before proceeding
    print(summary.counters.nodes_created)

不会自动重试。仅适用于
LOAD CSV
CALL {} IN TRANSACTIONS
或快速脚本。
python
with driver.session(database="neo4j") as session:
    result = session.run("CREATE (p:Person {name: $name})", name="Alice")
    summary = result.consume()   # 调用consume()以确保在继续操作前提交事务
    print(summary.counters.nodes_created)

Async API

异步API

Mirror of sync API — replace
GraphDatabase
with
AsyncGraphDatabase
,
await
every call.
python
from neo4j import AsyncGraphDatabase
import asyncio
与同步API镜像——将
GraphDatabase
替换为
AsyncGraphDatabase
,并为每个调用添加
await
python
from neo4j import AsyncGraphDatabase
import asyncio

Singleton — same rule as sync: never create per-request

单例——与同步规则相同:切勿为每个请求创建

driver = AsyncGraphDatabase.driver(URI, auth=AUTH)
async def main(): records, , _ = await driver.execute_query( "MATCH (p:Person) RETURN p.name AS name", database="neo4j", routing_=RoutingControl.READ, ) print([r["name"] for r in records]) await driver.close()
asyncio.run(main())

FastAPI lifespan pattern:
```python
from contextlib import asynccontextmanager
from fastapi import FastAPI

_driver = None

@asynccontextmanager
async def lifespan(app: FastAPI):
    global _driver
    _driver = AsyncGraphDatabase.driver(URI, auth=AUTH)
    await _driver.verify_connectivity()
    yield
    await _driver.close()

app = FastAPI(lifespan=lifespan)
Parallel queries with
asyncio.gather
:
python
results = await asyncio.gather(
    driver.execute_query("MATCH (a:Artist) RETURN a.name AS name", database_="neo4j"),
    driver.execute_query("MATCH (v:Venue)  RETURN v.name AS name",  database_="neo4j"),
)
Never use sync
GraphDatabase
in asyncio
— blocks the event loop.
Full async patterns → references/async.md

driver = AsyncGraphDatabase.driver(URI, auth=AUTH)
async def main(): records, , _ = await driver.execute_query( "MATCH (p:Person) RETURN p.name AS name", database="neo4j", routing_=RoutingControl.READ, ) print([r["name"] for r in records]) await driver.close()
asyncio.run(main())

FastAPI生命周期模式:
```python
from contextlib import asynccontextmanager
from fastapi import FastAPI

_driver = None

@asynccontextmanager
async def lifespan(app: FastAPI):
    global _driver
    _driver = AsyncGraphDatabase.driver(URI, auth=AUTH)
    await _driver.verify_connectivity()
    yield
    await _driver.close()

app = FastAPI(lifespan=lifespan)
使用
asyncio.gather
执行并行查询:
python
results = await asyncio.gather(
    driver.execute_query("MATCH (a:Artist) RETURN a.name AS name", database_="neo4j"),
    driver.execute_query("MATCH (v:Venue)  RETURN v.name AS name",  database_="neo4j"),
)
切勿在asyncio中使用同步
GraphDatabase
——会阻塞事件循环。
完整异步模式请查看 → references/async.md

Error Handling

错误处理

python
from neo4j.exceptions import (
    Neo4jError, ServiceUnavailable, TransientError,
    AuthError, ConstraintError,
)

try:
    driver.execute_query("...", database_="neo4j")
except AuthError:
    ...  # bad credentials
except ServiceUnavailable:
    ...  # no servers reachable
except ConstraintError as e:
    # unique/existence constraint violation — catch BEFORE Neo4jError (it's a subclass)
    print(e.code, e.message)
except TransientError as e:
    # raised only after retries exhausted (execute_query retries automatically)
    print(e.code)
except Neo4jError as e:
    print(e.code, e.message, e.gql_status)
Catch
ConstraintError
before
Neo4jError
— it is a subclass and will be swallowed otherwise.

python
from neo4j.exceptions import (
    Neo4jError, ServiceUnavailable, TransientError,
    AuthError, ConstraintError,
)

try:
    driver.execute_query("...", database_="neo4j")
except AuthError:
    ...  # 凭证错误
except ServiceUnavailable:
    ...  # 无法连接到服务器
except ConstraintError as e:
    # 唯一/存在约束违反——需在Neo4jError之前捕获(它是Neo4jError的子类)
    print(e.code, e.message)
except TransientError as e:
    # 仅在自动重试耗尽后抛出(execute_query会自动重试)
    print(e.code)
except Neo4jError as e:
    print(e.code, e.message, e.gql_status)
需先捕获
ConstraintError
再捕获
Neo4jError
——因为它是子类,否则会被后者覆盖。

Result Access & Null Safety

结果访问与空值安全

python
record = records[0]
record["name"]               # by key — KeyError if absent
record[0]                    # by index
record.get("name")           # None for absent key OR graph null
record.get("name", "Unknown")
d = record.data()            # dict — values still driver objects for Node/Rel/temporal types
record.data()
is not JSON-safe if result contains
Node
,
Relationship
,
Path
, or
neo4j.time.*
values. Project scalar fields in Cypher instead of returning whole nodes.
python
undefined
python
record = records[0]
record["name"]               # 通过键访问——键不存在时抛出KeyError
record[0]                    # 通过索引访问
record.get("name")           # 键不存在或图中值为null时返回None
record.get("name", "Unknown")
d = record.data()            # 转换为字典——Node/Rel/时间类型仍为驱动对象
如果结果包含
Node
Relationship
Path
neo4j.time.*
类型的值,
record.data()
无法直接序列化为JSON。请在Cypher查询中投影标量字段,而非返回整个节点。
python
undefined

❌ raises TypeError on json.dumps

❌ 使用json.dumps时会抛出TypeError

records, , _ = driver.execute_query("MATCH (p:Person) RETURN p", database="neo4j") json.dumps(records[0].data())
records, , _ = driver.execute_query("MATCH (p:Person) RETURN p", database="neo4j") json.dumps(records[0].data())

✅ project scalars

✅ 投影标量字段

records, , _ = driver.execute_query( "MATCH (p:Person) RETURN p.name AS name, p.age AS age", database="neo4j") json.dumps(records[0].data()) # safe

Node/Relationship/temporal access:
```python
node = record["p"]           # neo4j.graph.Node
node.element_id              # stable within this transaction only
node.labels                  # frozenset({'Person'})
dict(node)                   # all properties as plain dict

rel  = record["r"]           # neo4j.graph.Relationship
rel.type                     # 'KNOWS'

dt = record["created_at"]    # neo4j.time.DateTime
dt.to_native()               # datetime.datetime (loses sub-µs precision)
Full type mapping table → references/data-types.md

records, , _ = driver.execute_query( "MATCH (p:Person) RETURN p.name AS name, p.age AS age", database="neo4j") json.dumps(records[0].data()) # 安全可序列化

节点/关系/时间类型访问:
```python
node = record["p"]           # neo4j.graph.Node对象
node.element_id              # 仅在当前事务内稳定
node.labels                  # 冻结集合({'Person'})
dict(node)                   # 将所有属性转换为普通字典

rel  = record["r"]           # neo4j.graph.Relationship对象
rel.type                     # 关系类型,如'KNOWS'

dt = record["created_at"]    # neo4j.time.DateTime对象
dt.to_native()               # 转换为datetime.datetime(会丢失亚微秒精度)
完整类型映射表请查看 → references/data-types.md

Batch Writes with UNWIND

使用UNWIND进行批量写入

Pass
list[dict]
— only shape the driver serializes correctly for
UNWIND
.
python
people = [{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]
driver.execute_query(
    "UNWIND $rows AS row MERGE (p:Person {name: row.name}) SET p.age = row.age",
    rows=people,
    database_="neo4j",
)
Custom objects and dataclasses must be converted to
dict
before passing as parameters.

传递
list[dict]
类型数据——这是驱动为
UNWIND
序列化的正确格式。
python
people = [{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]
driver.execute_query(
    "UNWIND $rows AS row MERGE (p:Person {name: row.name}) SET p.age = row.age",
    rows=people,
    database_="neo4j",
)
自定义对象和数据类必须先转换为
dict
,再作为参数传递。

Performance

性能优化

  • Always set
    database_
    /
    database=
    — omitting triggers a home-database round-trip per call.
  • execute_read
    routes to replicas automatically; use
    routing_=RoutingControl.READ
    with
    execute_query
    .
  • Batch writes: one
    execute_write
    callback for the whole list > one tx per item.
  • Large results: stream lazily inside
    execute_read
    callback;
    execute_query
    is always eager.
Connection pool tuning:
python
driver = GraphDatabase.driver(URI, auth=AUTH,
    max_connection_pool_size=50,        # default 100
    connection_acquisition_timeout=30,  # seconds to wait for free connection
    max_connection_lifetime=3600,       # seconds; recycles stale connections
    connection_timeout=15,
    keep_alive=True,
)
Session exhaustion: each open session holds a connection. Always use
with driver.session(...) as session
.
Full performance patterns → references/performance.md

  • 始终设置
    database_
    /
    database=
    ——省略该参数会导致每次调用触发一次主数据库往返请求。
  • execute_read
    会自动将请求路由到副本节点;使用
    execute_query
    时可配合
    routing_=RoutingControl.READ
  • 批量写入:对整个列表使用一个
    execute_write
    回调 > 为每个项创建一个事务。
  • 大结果集:在
    execute_read
    回调内部惰性流式处理;
    execute_query
    始终是立即加载。
连接池调优:
python
driver = GraphDatabase.driver(URI, auth=AUTH,
    max_connection_pool_size=50,        # 默认值100
    connection_acquisition_timeout=30,  # 等待空闲连接的超时时间(秒)
    max_connection_lifetime=3600,       # 连接最大存活时间(秒);回收过期连接
    connection_timeout=15,
    keep_alive=True,
)
会话耗尽:每个打开的会话会占用一个连接。请始终使用
with driver.session(...) as session
完整性能优化模式请查看 → references/performance.md

Common Errors

常见错误

MistakeFix
f-string /
.format()
Cypher params
Use
$param
placeholders always
Param name ending with
_
Pass via
parameters_={"key_": val}
Omitting
database_
Always set — saves a round-trip every call
Returning
Result
from tx callback
Consume to
list
inside callback
Side effects in
execute_read/write
callback
Move outside — callback may retry
Passing dataclass/Pydantic as paramConvert to
dict
first
UNWIND
with list of objects
list[dict]
only
record.get()
for absent-key detection
"key" in record.keys()
for absent;
.get()
returns
None
for both absent and graph null
No
.consume()
after
session.run()
Commit timing undefined; call
.consume()
Sync driver inside asyncioUse
AsyncGraphDatabase
— sync blocks event loop
Async driver created per requestSingleton — create once at startup
Leaked sessions
with driver.session(...) as session
always
json.dumps(record.data())
with node/temporal
Project scalars in Cypher or convert explicitly
result["name"]
on
EagerResult
Index
result.records[0]["name"]
or unpack
records, _, _ = ...
Result.single()
returns None for 0 results
It raises — use
single(strict=False)
@unit_of_work
on lambda
Use named function
Neo4jError
caught before
ConstraintError
Catch
ConstraintError
first — it's a subclass
neo4j-driver
package name
Package is
neo4j
since v6;
neo4j-driver
deprecated

错误操作修复方法
使用f-string /
.format()
拼接Cypher参数
始终使用
$param
占位符
参数名称以
_
结尾
通过
parameters_={"key_": val}
传递
省略
database_
参数
始终设置该参数——每次调用可减少一次往返请求
从事务回调中返回
Result
在回调内部将结果消费为
list
execute_read/write
回调中包含副作用
将副作用移到回调外部——回调可能会重试
将数据类/Pydantic对象作为参数传递先转换为
dict
UNWIND
使用对象列表
仅使用
list[dict]
类型
使用
record.get()
检测键是否存在
使用
"key" in record.keys()
检测键是否存在;
.get()
在键不存在或图中值为null时均返回None
session.run()
后未调用
.consume()
提交时间不确定;请调用
.consume()
在asyncio中使用同步驱动使用
AsyncGraphDatabase
——同步驱动会阻塞事件循环
为每个请求创建异步驱动使用单例——在应用启动时创建一次
会话泄漏始终使用
with driver.session(...) as session
对包含节点/时间类型的
record.data()
使用
json.dumps
在Cypher中投影标量字段或显式转换
EagerResult
上使用
result["name"]
使用
result.records[0]["name"]
或解包
records, _, _ = ...
Result.single()
在零结果时返回None
它会抛出异常——使用
single(strict=False)
在lambda上使用
@unit_of_work
使用命名函数
先捕获
Neo4jError
再捕获
ConstraintError
先捕获
ConstraintError
——它是子类
使用
neo4j-driver
包名称
自v6起包名称为
neo4j
neo4j-driver
已废弃

References

参考资料

Load on demand:
  • references/async.md — full async patterns: managed transactions, result methods, concurrency
  • references/data-types.md — complete Python↔Cypher type mapping, temporal conversion, graph object API, spatial types (CartesianPoint/WGS84Point)
  • references/performance.md — connection pool, lazy streaming, threading vs asyncio, bookmarks/causal consistency
  • references/transactions.md — explicit transactions, rollback, commit uncertainty,
    unit_of_work
    details
Docs:

按需加载:
  • references/async.md —— 完整异步模式:托管事务、结果方法、并发
  • references/data-types.md —— 完整Python↔Cypher类型映射、时间转换、图对象API、空间类型(CartesianPoint/WGS84Point)
  • references/performance.md —— 连接池、惰性流式处理、线程vs asyncio、书签/因果一致性
  • references/transactions.md —— 显式事务、回滚、提交不确定性、
    unit_of_work
    细节
官方文档:

Checklist

检查清单

  • Package installed as
    neo4j
    (not
    neo4j-driver
    )
  • One Driver instance created at startup; shared everywhere
  • verify_connectivity()
    called at startup
  • database_
    /
    database=
    set on every call
  • $param
    placeholders used — no f-strings or
    .format()
  • Result consumed inside tx callback (not returned raw)
  • Sessions used as context managers (
    with driver.session(...) as session
    )
  • ConstraintError
    caught before
    Neo4jError
  • AsyncGraphDatabase
    used in asyncio code (not sync driver)
  • Async driver created once at app startup (not per request)
  • Side effects outside
    execute_read/write
    callbacks
  • UNWIND batches use
    list[dict]
  • 安装的包为
    neo4j
    (而非
    neo4j-driver
  • 在应用启动时创建一个Driver实例,并在各处共享
  • 在启动时调用
    verify_connectivity()
  • 每次调用都设置
    database_
    /
    database=
  • 使用
    $param
    占位符——不使用f-strings或
    .format()
  • 在事务回调内部消费结果(不直接返回原始Result)
  • 使用上下文管理器管理会话(
    with driver.session(...) as session
  • 先捕获
    ConstraintError
    再捕获
    Neo4jError
  • 在asyncio代码中使用
    AsyncGraphDatabase
    (而非同步驱动)
  • 在应用启动时创建一次异步驱动(不为每个请求创建)
  • 将副作用移到
    execute_read/write
    回调外部
  • UNWIND批量处理使用
    list[dict]
    类型