neo4j-driver-go-skill

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

When to Use

适用场景

  • Writing Go code that connects to Neo4j
  • Setting up
    neo4j.NewDriver()
    ,
    ExecuteQuery()
    , or session/transaction patterns
  • Debugging connection errors, result iteration, type assertions, causal consistency
  • 编写连接Neo4j的Go代码
  • 配置
    neo4j.NewDriver()
    ExecuteQuery()
    或会话/事务模式
  • 调试连接错误、结果迭代、类型断言、因果一致性问题

When NOT to Use

不适用场景

  • Writing/optimizing Cypher
    neo4j-cypher-skill
  • v5→v6 migration steps
    neo4j-migration-skill

  • 编写/优化Cypher查询 → 使用
    neo4j-cypher-skill
  • v5→v6版本迁移步骤 → 使用
    neo4j-migration-skill

Installation

安装

bash
go get github.com/neo4j/neo4j-go-driver/v6
Import:
github.com/neo4j/neo4j-go-driver/v6/neo4j
v5→v6 rename (deprecated aliases still compile, remove before v7):
v5v6
neo4j.NewDriverWithContext(...)
neo4j.NewDriver(...)
neo4j.DriverWithContext
neo4j.Driver

bash
go get github.com/neo4j/neo4j-go-driver/v6
导入:
github.com/neo4j/neo4j-go-driver/v6/neo4j
v5→v6重命名说明(已废弃的别名仍可编译,但v7版本前需移除):
v5v6
neo4j.NewDriverWithContext(...)
neo4j.NewDriver(...)
neo4j.DriverWithContext
neo4j.Driver

Environment Variables

环境变量

go
import "os"

uri      := getEnv("NEO4J_URI",      "neo4j://localhost:7687")
user     := getEnv("NEO4J_USERNAME", "neo4j")
password := getEnv("NEO4J_PASSWORD", "")
database := getEnv("NEO4J_DATABASE", "neo4j")

func getEnv(key, fallback string) string {
    if v := os.Getenv(key); v != "" { return v }
    return fallback
}
Use godotenv to load
.env
in dev:
godotenv.Load()
.
.env
in
.gitignore
.

go
import "os"

uri      := getEnv("NEO4J_URI",      "neo4j://localhost:7687")
user     := getEnv("NEO4J_USERNAME", "neo4j")
password := getEnv("NEO4J_PASSWORD", "")
database := getEnv("NEO4J_DATABASE", "neo4j")

func getEnv(key, fallback string) string {
    if v := os.Getenv(key); v != "" { return v }
    return fallback
}
开发环境中可使用godotenv加载
.env
文件:
godotenv.Load()
。需将
.env
添加到
.gitignore
中。

Driver Lifecycle

驱动生命周期

One
Driver
per application. Goroutine-safe, connection-pooled, expensive to create.
go
func NewNeo4jDriver(uri, user, password string) (neo4j.Driver, error) {
    driver, err := neo4j.NewDriver(
        uri, // "neo4j+s://xxx.databases.neo4j.io" for Aura
        neo4j.BasicAuth(user, password, ""),
    )
    if err != nil {
        return nil, fmt.Errorf("create driver: %w", err)
    }
    ctx := context.Background()
    if err := driver.VerifyConnectivity(ctx); err != nil {
        driver.Close(ctx)
        return nil, fmt.Errorf("verify connectivity: %w", err)
    }
    return driver, nil
}

// In main / app teardown:
defer driver.Close(ctx)
❌ Never create driver per-request. Create once at startup; share across goroutines.
URI schemes:
neo4j+s://
(Aura/TLS+routing),
neo4j://
(plain+routing),
bolt+s://
(TLS+single),
bolt://
(plain+single).

每个应用仅需创建一个
Driver
实例。该实例支持协程安全、连接池化,创建成本较高。
go
func NewNeo4jDriver(uri, user, password string) (neo4j.Driver, error) {
    driver, err := neo4j.NewDriver(
        uri, // Aura环境请使用 "neo4j+s://xxx.databases.neo4j.io"
        neo4j.BasicAuth(user, password, ""),
    )
    if err != nil {
        return nil, fmt.Errorf("create driver: %w", err)
    }
    ctx := context.Background()
    if err := driver.VerifyConnectivity(ctx); err != nil {
        driver.Close(ctx)
        return nil, fmt.Errorf("verify connectivity: %w", err)
    }
    return driver, nil
}

// 在main函数/应用销毁阶段:
defer driver.Close(ctx)
❌ 绝不要为每个请求创建驱动实例。应在启动时创建一次,在协程间共享使用。
URI协议:
neo4j+s://
(Aura环境/TLS+路由)、
neo4j://
(明文+路由)、
bolt+s://
(TLS+单节点)、
bolt://
(明文+单节点)。

Choosing the Right API

选择合适的API

APIUse whenAuto-retryLazy results
neo4j.ExecuteQuery()
Most queries — simple default❌ eager
session.ExecuteRead/Write()
Large result sets / streaming
session.BeginTransaction()
Spans multiple functions / ext coordination
session.Run()
CALL IN TRANSACTIONS
/ auto-commit only
CALL { … } IN TRANSACTIONS
and
USING PERIODIC COMMIT
manage their own transactions — use
session.Run()
. They fail inside managed transactions.

API适用场景自动重试延迟加载结果
neo4j.ExecuteQuery()
大多数查询——简单默认选项❌ 立即加载
session.ExecuteRead/Write()
大型结果集/流式处理
session.BeginTransaction()
事务操作跨多个函数/需外部协调
session.Run()
仅用于
CALL IN TRANSACTIONS
/自动提交场景
CALL { … } IN TRANSACTIONS
USING PERIODIC COMMIT
会自行管理事务——需使用
session.Run()
。在托管事务中执行这些语句会失败。

ExecuteQuery (Recommended Default)

ExecuteQuery(推荐默认使用)

Manages sessions, transactions, retries, and bookmarks automatically.
go
result, err := neo4j.ExecuteQuery(ctx, driver,
    `MATCH (p:Person {name: $name})-[:KNOWS]->(friend)
     RETURN friend.name AS name`,
    map[string]any{"name": "Alice"},
    neo4j.EagerResultTransformer,
    neo4j.ExecuteQueryWithDatabase("neo4j"),       // always specify
    neo4j.ExecuteQueryWithReadersRouting(),         // for read queries
)
if err != nil {
    return fmt.Errorf("query people: %w", err)
}

for _, record := range result.Records {
    name, _ := record.Get("name")
    fmt.Println(name)
}
fmt.Println(result.Summary.Counters().NodesCreated())
Key options:
go
neo4j.ExecuteQueryWithDatabase("mydb")          // required for performance
neo4j.ExecuteQueryWithReadersRouting()           // route reads to replicas
neo4j.ExecuteQueryWithImpersonatedUser("jane")  // impersonate
neo4j.ExecuteQueryWithoutBookmarkManager()       // opt out of causal consistency
❌ Never concatenate user input into query strings. Always use
map[string]any
parameters.

自动管理会话、事务、重试以及书签。
go
result, err := neo4j.ExecuteQuery(ctx, driver,
    `MATCH (p:Person {name: $name})-[:KNOWS]->(friend)
     RETURN friend.name AS name`,
    map[string]any{"name": "Alice"},
    neo4j.EagerResultTransformer,
    neo4j.ExecuteQueryWithDatabase("neo4j"),       // 务必指定
    neo4j.ExecuteQueryWithReadersRouting(),         // 只读查询使用
)
if err != nil {
    return fmt.Errorf("query people: %w", err)
}

for _, record := range result.Records {
    name, _ := record.Get("name")
    fmt.Println(name)
}
fmt.Println(result.Summary.Counters().NodesCreated())
关键选项:
go
neo4j.ExecuteQueryWithDatabase("mydb")          // 对性能至关重要,必须指定
neo4j.ExecuteQueryWithReadersRouting()           // 将读请求路由到副本节点
neo4j.ExecuteQueryWithImpersonatedUser("jane")  // 模拟用户
neo4j.ExecuteQueryWithoutBookmarkManager()       // 禁用因果一致性
❌ 绝不要将用户输入拼接进查询字符串。始终使用
map[string]any
参数。

Managed Transactions (Session-Based)

托管事务(基于会话)

Use for lazy streaming (large result sets) or callback-level control.
go
session := driver.NewSession(ctx, neo4j.SessionConfig{
    DatabaseName: "neo4j", // always specify
    AccessMode:   neo4j.AccessModeRead,
})
defer session.Close(ctx)

result, err := session.ExecuteRead(ctx,
    func(tx neo4j.ManagedTransaction) (any, error) {
        res, err := tx.Run(ctx,
            `MATCH (p:Person) RETURN p.name AS name LIMIT $limit`,
            map[string]any{"limit": 100},
        )
        if err != nil {
            return nil, err
        }
        var names []string
        for res.Next(ctx) { // lazy — don't Collect() on large sets
            name, _ := res.Record().Get("name")
            names = append(names, name.(string))
        }
        return names, res.Err()
    },
)
❌ No side effects in callback — retried on transient failures.
ExecuteRead
→ replicas.
ExecuteWrite
→ cluster leader.

适用于延迟加载流式处理(大型结果集)或需要回调级控制的场景。
go
session := driver.NewSession(ctx, neo4j.SessionConfig{
    DatabaseName: "neo4j", // 务必指定
    AccessMode:   neo4j.AccessModeRead,
})
defer session.Close(ctx)

result, err := session.ExecuteRead(ctx,
    func(tx neo4j.ManagedTransaction) (any, error) {
        res, err := tx.Run(ctx,
            `MATCH (p:Person) RETURN p.name AS name LIMIT $limit`,
            map[string]any{"limit": 100},
        )
        if err != nil {
            return nil, err
        }
        var names []string
        for res.Next(ctx) { // 延迟加载——大型数据集请勿使用Collect()
            name, _ := res.Record().Get("name")
            names = append(names, name.(string))
        }
        return names, res.Err()
    },
)
❌ 回调函数中不要包含副作用——临时失败时会重试。
ExecuteRead
→ 请求路由到副本节点。
ExecuteWrite
→ 请求路由到集群主节点。

Explicit Transactions

显式事务

Use when transaction work spans multiple functions or requires external coordination.
go
session := driver.NewSession(ctx, neo4j.SessionConfig{DatabaseName: "neo4j"})
defer session.Close(ctx)

tx, err := session.BeginTransaction(ctx)
if err != nil {
    return err
}
if err := doPartA(ctx, tx); err != nil {
    tx.Rollback(ctx)
    return err
}
if err := doPartB(ctx, tx); err != nil {
    tx.Rollback(ctx)
    return err
}
return tx.Commit(ctx)
❌ Not auto-retried. Caller handles retry. Prefer managed transactions unless you need explicit control.

适用于事务操作跨多个函数或需要外部协调的场景。
go
session := driver.NewSession(ctx, neo4j.SessionConfig{DatabaseName: "neo4j"})
defer session.Close(ctx)

tx, err := session.BeginTransaction(ctx)
if err != nil {
    return err
}
if err := doPartA(ctx, tx); err != nil {
    tx.Rollback(ctx)
    return err
}
if err := doPartB(ctx, tx); err != nil {
    tx.Rollback(ctx)
    return err
}
return tx.Commit(ctx)
❌ 不会自动重试。需由调用方处理重试逻辑。除非需要显式控制,否则优先使用托管事务。

Error Handling

错误处理

go
result, err := neo4j.ExecuteQuery(...)
if err != nil {
    var neo4jErr *neo4j.Neo4jError
    if errors.As(err, &neo4jErr) {
        slog.Error("database error", "code", neo4jErr.Code, "msg", neo4jErr.Msg)
    }
    var connErr *neo4j.ConnectivityError
    if errors.As(err, &connErr) {
        slog.Error("connectivity error", "err", connErr)
    }
    return fmt.Errorf("execute query: %w", err)
}
Helpers:
go
neo4j.IsNeo4jError(err)                // server-side Cypher/database error
neo4j.IsTransactionExecutionLimit(err) // managed tx retries exhausted
In managed tx callback: return error → driver retries if transient.
ConnectivityError
at startup: check URI scheme, credentials, firewall.

go
result, err := neo4j.ExecuteQuery(...)
if err != nil {
    var neo4jErr *neo4j.Neo4jError
    if errors.As(err, &neo4jErr) {
        slog.Error("database error", "code", neo4jErr.Code, "msg", neo4jErr.Msg)
    }
    var connErr *neo4j.ConnectivityError
    if errors.As(err, &connErr) {
        slog.Error("connectivity error", "err", connErr)
    }
    return fmt.Errorf("execute query: %w", err)
}
辅助函数:
go
neo4j.IsNeo4jError(err)                // 服务端Cypher/数据库错误
neo4j.IsTransactionExecutionLimit(err) // 托管事务重试次数耗尽
在托管事务回调中:返回错误→驱动会在临时失败时重试。 启动时出现
ConnectivityError
:检查URI协议、凭证、防火墙设置。

Data Types

数据类型映射

CypherGo
Integer
int64
Float
float64
String
string
Boolean
bool
List
[]any
Map
map[string]any
Node
neo4j.Node
Relationship
neo4j.Relationship
Path
neo4j.Path
Date
neo4j.Date
DateTime
neo4j.Time
Duration
neo4j.Duration
null
nil
go
// Typed extraction (v6+, preferred):
neo4j.GetRecordValue[string](record, "name")

// Manual extraction:
rawAge, ok := record.Get("age")
if !ok { return errors.New("missing 'age' field") }
age := rawAge.(int64) // Neo4j integers → int64

// Node access:
rawNode, _ := record.Get("p")
node := rawNode.(neo4j.Node)
name := node.Props["name"].(string)
labels := node.Labels // []string
❌ Always check
ok
from
record.Get()
before type-asserting — panics on missing key. ❌ After lazy
for res.Next(ctx)
loop, always check
res.Err()
.

Cypher类型Go类型
Integer
int64
Float
float64
String
string
Boolean
bool
List
[]any
Map
map[string]any
Node
neo4j.Node
Relationship
neo4j.Relationship
Path
neo4j.Path
Date
neo4j.Date
DateTime
neo4j.Time
Duration
neo4j.Duration
null
nil
go
// 类型化提取(v6+,推荐使用):
neo4j.GetRecordValue[string](record, "name")

// 手动提取:
rawAge, ok := record.Get("age")
if !ok { return errors.New("missing 'age' field") }
age := rawAge.(int64) // Neo4j整数对应Go的int64

// 节点访问:
rawNode, _ := record.Get("p")
node := rawNode.(neo4j.Node)
name := node.Props["name"].(string)
labels := node.Labels // []string
❌ 在类型断言前务必检查
record.Get()
返回的
ok
值——缺少键会导致panic。 ❌ 在延迟加载的
for res.Next(ctx)
循环结束后,务必检查
res.Err()

Key Patterns

核心模式

Context — always propagate

上下文——始终传递

go
ctx, cancel := context.WithTimeout(parentCtx, 5*time.Second)
defer cancel()
// pass ctx to all driver calls
context.Background()
has no deadline — slow queries block indefinitely.
go
ctx, cancel := context.WithTimeout(parentCtx, 5*time.Second)
defer cancel()
// 将ctx传递给所有驱动调用
context.Background()
没有超时限制——慢查询会无限期阻塞。

Batching Writes

批量写入

go
// Bad: one transaction per record
for _, item := range items {
    neo4j.ExecuteQuery(ctx, driver, writeQuery, item, ...)
}

// Good: UNWIND batch in one transaction
neo4j.ExecuteQuery(ctx, driver,
    `UNWIND $items AS item
     MERGE (n:Node {id: item.id})
     SET n += item`,
    map[string]any{"items": items},
    neo4j.EagerResultTransformer,
    neo4j.ExecuteQueryWithDatabase("neo4j"),
)
go
// 错误示例:每条记录对应一个事务
for _, item := range items {
    neo4j.ExecuteQuery(ctx, driver, writeQuery, item, ...)
}

// 正确示例:在一个事务中使用UNWIND批量处理
neo4j.ExecuteQuery(ctx, driver,
    `UNWIND $items AS item
     MERGE (n:Node {id: item.id})
     SET n += item`,
    map[string]any{"items": items},
    neo4j.EagerResultTransformer,
    neo4j.ExecuteQueryWithDatabase("neo4j"),
)

Generic Helpers (v6+)

通用辅助函数(v6+)

Prefer type-safe helpers over manual assertions:
go
// GetRecordValue[T] — extract + cast in one call
name, isNil, err := neo4j.GetRecordValue[string](record, "name")
// isNil=true when OPTIONAL MATCH returned null; err != nil when key absent or wrong type

// CollectTWithContext — map all records to a slice
people, err := neo4j.CollectTWithContext(ctx, result, func(record *neo4j.Record) (Person, error) {
    name, _, err := neo4j.GetRecordValue[string](record, "name")
    age, _, _   := neo4j.GetRecordValue[int64](record, "age")
    return Person{Name: name, Age: int(age)}, err
})

// SingleTWithContext — expect exactly one record (error if 0 or 2+)
person, err := neo4j.SingleTWithContext(ctx, result, func(record *neo4j.Record) (Person, error) {
    name, _, _ := neo4j.GetRecordValue[string](record, "name")
    return Person{Name: name}, nil
})

// GetProperty — typed property from Node or Relationship
node, _, _ := neo4j.GetRecordValue[neo4j.Node](record, "p")
nameVal, err := neo4j.GetProperty[string](node, "name")
优先使用类型安全的辅助函数,而非手动断言:
go
// GetRecordValue[T] — 一步完成提取与类型转换
name, isNil, err := neo4j.GetRecordValue[string](record, "name")
// isNil=true表示OPTIONAL MATCH返回null;err!=nil表示键不存在或类型错误

// CollectTWithContext — 将所有记录映射为切片
people, err := neo4j.CollectTWithContext(ctx, result, func(record *neo4j.Record) (Person, error) {
    name, _, err := neo4j.GetRecordValue[string](record, "name")
    age, _, _   := neo4j.GetRecordValue[int64](record, "age")
    return Person{Name: name, Age: int(age)}, err
})

// SingleTWithContext — 期望恰好一条记录(0条或2条以上会报错)
person, err := neo4j.SingleTWithContext(ctx, result, func(record *neo4j.Record) (Person, error) {
    name, _, _ := neo4j.GetRecordValue[string](record, "name")
    return Person{Name: name}, nil
})

// GetProperty — 从Node或Relationship中提取类型化属性
node, _, _ := neo4j.GetRecordValue[neo4j.Node](record, "p")
nameVal, err := neo4j.GetProperty[string](node, "name")

Spatial Types

空间类型

go
// 2D Cartesian (SRID 7203), 3D Cartesian (SRID 9157)
pt2d := neo4j.Point2D{X: 1.23, Y: 4.56, SpatialRefId: 7203}
pt3d := neo4j.Point3D{X: 1.23, Y: 4.56, Z: 7.89, SpatialRefId: 9157}

// 2D WGS-84 (SRID 4326), 3D WGS-84 (SRID 4979)
london := neo4j.Point2D{X: -0.118092, Y: 51.509865, SpatialRefId: 4326}
shard  := neo4j.Point3D{X: -0.0865, Y: 51.5045, Z: 310, SpatialRefId: 4979}

// Pass as parameter
result, err := neo4j.ExecuteQuery(ctx, driver,
    "CREATE (p:Place {location: $loc})",
    map[string]any{"loc": london},
    neo4j.EagerResultTransformer,
    neo4j.ExecuteQueryWithDatabase("neo4j"),
)

// Read from result — assert to Point2D or Point3D
raw, _ := record.Get("location")
if p2d, ok := raw.(neo4j.Point2D); ok {
    fmt.Printf("lon=%f lat=%f srid=%d\n", p2d.X, p2d.Y, p2d.SpatialRefId)
}

// Distance (same SRID only)
result, _ = neo4j.ExecuteQuery(ctx, driver,
    "RETURN point.distance($p1, $p2) AS distance",
    map[string]any{"p1": pt2d, "p2": neo4j.Point2D{X: 10, Y: 10, SpatialRefId: 7203}},
    neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase("neo4j"),
)
dist, _ := result.Records[0].Get("distance")
fmt.Println(dist.(float64))
go
// 2D笛卡尔坐标(SRID 7203),3D笛卡尔坐标(SRID 9157)
pt2d := neo4j.Point2D{X: 1.23, Y: 4.56, SpatialRefId: 7203}
pt3d := neo4j.Point3D{X: 1.23, Y: 4.56, Z: 7.89, SpatialRefId: 9157}

// 2D WGS-84(SRID 4326),3D WGS-84(SRID 4979)
london := neo4j.Point2D{X: -0.118092, Y: 51.509865, SpatialRefId: 4326}
shard  := neo4j.Point3D{X: -0.0865, Y: 51.5045, Z: 310, SpatialRefId: 4979}

// 作为参数传递
result, err := neo4j.ExecuteQuery(ctx, driver,
    "CREATE (p:Place {location: $loc})",
    map[string]any{"loc": london},
    neo4j.EagerResultTransformer,
    neo4j.ExecuteQueryWithDatabase("neo4j"),
)

// 从结果中读取——断言为Point2D或Point3D
raw, _ := record.Get("location")
if p2d, ok := raw.(neo4j.Point2D); ok {
    fmt.Printf("lon=%f lat=%f srid=%d\n", p2d.X, p2d.Y, p2d.SpatialRefId)
}

// 计算距离(仅支持相同SRID)
result, _ = neo4j.ExecuteQuery(ctx, driver,
    "RETURN point.distance($p1, $p2) AS distance",
    map[string]any{"p1": pt2d, "p2": neo4j.Point2D{X: 10, Y: 10, SpatialRefId: 7203}},
    neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase("neo4j"),
)
dist, _ := result.Records[0].Get("distance")
fmt.Println(dist.(float64))

Always Specify Database

务必指定数据库

go
neo4j.ExecuteQueryWithDatabase("neo4j")    // in ExecuteQuery
neo4j.SessionConfig{DatabaseName: "neo4j"} // in sessions
Omitting costs a network round-trip per call to resolve home database.
go
neo4j.ExecuteQueryWithDatabase("neo4j")    // 在ExecuteQuery中指定
neo4j.SessionConfig{DatabaseName: "neo4j"} // 在会话中指定
省略数据库名会导致每次调用都需要额外的网络往返来解析默认数据库。

Causal Consistency

因果一致性

ExecuteQuery
manages bookmarks automatically — no action needed for sequential calls. Cross-session (parallel workers): combine bookmarks explicitly — see references/repository-pattern.md.

ExecuteQuery
会自动管理书签——顺序调用时无需额外操作。 跨会话(并行工作者):需显式合并书签——详见references/repository-pattern.md

Common Errors

常见错误

Error / SymptomCauseFix
ConnectivityError
at startup
URI wrong / TLS mismatch / firewallCheck scheme (
neo4j+s://
for Aura), credentials, port 7687
ConnectivityError
mid-run
Pool exhaustedIncrease
MaxConnectionPoolSize
; check for leaked sessions
Panic on type assertion
record.Get()
returned nil/wrong type
Use
neo4j.GetRecordValue[T]()
or check
ok
first
res.Err()
non-nil after loop
Network error mid-streamHandle error; re-run transaction
Callback retried unexpectedlySide effect inside managed txMove side effects outside callback
Context deadline exceededNo timeout on contextUse
context.WithTimeout
0 results, query looks correctWrong
DatabaseName
Always set
DatabaseName
in config
CALL IN TRANSACTIONS
fails
Run inside managed txUse
session.Run()
(auto-commit)

错误/症状原因解决方法
启动时出现
ConnectivityError
URI错误/TLS不匹配/防火墙拦截检查协议(Aura环境使用
neo4j+s://
)、凭证、7687端口
运行中出现
ConnectivityError
连接池耗尽增大
MaxConnectionPoolSize
;检查是否存在会话泄漏
类型断言导致panic
record.Get()
返回nil或错误类型
使用
neo4j.GetRecordValue[T]()
或先检查
ok
循环结束后
res.Err()
非空
流式处理中出现网络错误处理错误;重新执行事务
回调函数意外重试托管事务回调中包含副作用将副作用移到回调函数外部
上下文超时未设置上下文超时使用
context.WithTimeout
查询语句正确但返回0结果
DatabaseName
设置错误
始终在配置中设置
DatabaseName
CALL IN TRANSACTIONS
执行失败
在托管事务中运行使用
session.Run()
(自动提交)

References

参考资料

Load on demand: Load on demand:
  • references/advanced-config.md — connection pool tuning, custom address resolver, notification config, Bolt logging, auth options, URI scheme table
  • references/repository-pattern.md — repository wrapper pattern, cross-session causal consistency with bookmarks
按需加载:
  • references/advanced-config.md — 连接池调优、自定义地址解析器、通知配置、Bolt日志、认证选项、URI协议对照表
  • references/repository-pattern.md — 仓库包装模式、跨会话书签因果一致性

WebFetch

在线资源

NeedURL
Go driver manual
https://neo4j.com/docs/go-manual/current/
API reference
https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v6/neo4j

需求链接
Go驱动手册
https://neo4j.com/docs/go-manual/current/
API参考
https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v6/neo4j

Checklist

检查清单

  • One driver created at startup; shared across goroutines;
    defer driver.Close(ctx)
  • driver.VerifyConnectivity(ctx)
    called at startup
  • DatabaseName
    set in all
    SessionConfig
    /
    ExecuteQueryWithDatabase
  • context.WithTimeout
    used for production queries
  • map[string]any
    parameters used — no string interpolation
  • ExecuteQueryWithReadersRouting()
    on read-only
    ExecuteQuery
    calls
  • res.Err()
    checked after lazy
    for result.Next(ctx)
    loop
  • Type assertions guarded (use
    GetRecordValue[T]
    or check
    ok
    )
  • No side effects inside managed transaction callbacks
  • session.Run()
    used for
    CALL IN TRANSACTIONS
    / auto-commit queries
  • Sessions closed with
    defer session.Close(ctx)
  • 启动时创建一个驱动实例,在协程间共享,使用
    defer driver.Close(ctx)
    确保关闭
  • 启动时调用
    driver.VerifyConnectivity(ctx)
  • 所有
    SessionConfig
    /
    ExecuteQueryWithDatabase
    中都设置
    DatabaseName
  • 生产环境查询使用
    context.WithTimeout
  • 使用
    map[string]any
    参数——禁止字符串插值
  • 只读
    ExecuteQuery
    调用使用
    ExecuteQueryWithReadersRouting()
  • 延迟加载的
    for result.Next(ctx)
    循环结束后检查
    res.Err()
  • 类型断言前进行防护(使用
    GetRecordValue[T]
    或检查
    ok
    值)
  • 托管事务回调中不包含副作用
  • CALL IN TRANSACTIONS
    /自动提交查询使用
    session.Run()
  • 使用
    defer session.Close(ctx)
    关闭会话