使用 Neo4j 官方包,处理查询
Last active
May 6, 2025 02:12
-
-
Save cod7ce/48626d662d2ac1edbef974f13ff6a012 to your computer and use it in GitHub Desktop.
Neo4j 在 Go 生态中的基本使用
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| module Neo4j | |
| go 1.21.12 | |
| require ( | |
| github.com/neo4j/neo4j-go-driver/v5 v5.28.0 | |
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "context" | |
| "fmt" | |
| "log" | |
| "time" | |
| "github.com/neo4j/neo4j-go-driver/v5/neo4j" | |
| ) | |
| // Neo4jPool 连接池结构 | |
| type Neo4jPool struct { | |
| driver neo4j.DriverWithContext | |
| pool chan neo4j.SessionWithContext | |
| size int | |
| } | |
| // Neo4jConfig 配置结构 | |
| type Neo4jConfig struct { | |
| URI string // "bolt://localhost:7687" | |
| Username string | |
| Password string | |
| MaxConn int | |
| } | |
| // NewNeo4jPool 创建新的连接池 | |
| func NewNeo4jPool(config *Neo4jConfig) (*Neo4jPool, error) { | |
| // auth := neo4j.BasicAuth(config.Username, config.Password, "") | |
| driver, err := neo4j.NewDriverWithContext(config.URI, neo4j.NoAuth()) | |
| if err != nil { | |
| return nil, fmt.Errorf("failed to create driver: %v", err) | |
| } | |
| pool := &Neo4jPool{ | |
| driver: driver, | |
| pool: make(chan neo4j.SessionWithContext, config.MaxConn), | |
| size: config.MaxConn, | |
| } | |
| // 初始化连接池 | |
| for i := 0; i < pool.size; i++ { | |
| session := driver.NewSession(context.Background(), neo4j.SessionConfig{}) | |
| pool.pool <- session | |
| } | |
| return pool, nil | |
| } | |
| // GetSession 从连接池获取会话 | |
| func (p *Neo4jPool) GetSession() neo4j.SessionWithContext { | |
| return <-p.pool | |
| } | |
| // ReleaseSession 释放会话回连接池 | |
| func (p *Neo4jPool) ReleaseSession(session neo4j.SessionWithContext) { | |
| p.pool <- session | |
| } | |
| // Close 关闭连接池 | |
| func (p *Neo4jPool) Close() { | |
| ctx := context.Background() | |
| close(p.pool) | |
| for session := range p.pool { | |
| session.Close(ctx) | |
| } | |
| p.driver.Close(ctx) | |
| } | |
| // ExecuteInTransaction 在事务中执行查询 | |
| func (p *Neo4jPool) ExecuteInTransaction(ctx context.Context, queries []string, params []map[string]interface{}) error { | |
| session := p.GetSession() | |
| defer p.ReleaseSession(session) | |
| _, err := session.ExecuteWrite(ctx, func(tx neo4j.ManagedTransaction) (interface{}, error) { | |
| for i, query := range queries { | |
| result, err := tx.Run(ctx, query, params[i]) | |
| if err != nil { | |
| return nil, fmt.Errorf("failed to execute query %d: %v", i, err) | |
| } | |
| _, err = result.Consume(ctx) | |
| if err != nil { | |
| return nil, fmt.Errorf("failed to consume result %d: %v", i, err) | |
| } | |
| } | |
| return nil, nil | |
| }) | |
| return err | |
| } | |
| // QueryWithRetry 带重试的查询执行 | |
| func (p *Neo4jPool) QueryWithRetry(ctx context.Context, queries []string, params []map[string]interface{}, maxRetries int) error { | |
| var err error | |
| for i := 0; i < maxRetries; i++ { | |
| err = p.ExecuteInTransaction(ctx, queries, params) | |
| if err == nil { | |
| return nil | |
| } | |
| // 检查是否需要重试 | |
| if !isRetryableError(err) { | |
| return err | |
| } | |
| log.Printf("Retry %d: %v", i+1, err) | |
| time.Sleep(time.Second * time.Duration(i+1)) | |
| } | |
| return fmt.Errorf("max retries reached: %v", err) | |
| } | |
| // isRetryableError 判断错误是否需要重试 | |
| func isRetryableError(err error) bool { | |
| // 这里可以根据实际需求添加更多的错误类型判断 | |
| return err != nil | |
| } | |
| func main() { | |
| // 配置 | |
| config := &Neo4jConfig{ | |
| URI: "bolt://localhost:7687", | |
| Username: "neo4j", | |
| Password: "password", | |
| MaxConn: 10, | |
| } | |
| // 创建连接池 | |
| pool, err := NewNeo4jPool(config) | |
| if err != nil { | |
| log.Fatalf("Failed to create pool: %v", err) | |
| } | |
| defer pool.Close() | |
| // 准备查询和参数 | |
| teamUUID := "Team1" | |
| queries := []string{ | |
| "CREATE (u:" + teamUUID + ":User {name: $name, age: $age})", | |
| "MATCH (u:" + teamUUID + ":User {name: $name}) CREATE (u)-[:FOLLOWS]->(f:User {name: $friendName})", | |
| } | |
| params := []map[string]interface{}{ | |
| { | |
| "name": "Alice", | |
| "age": 25, | |
| }, | |
| { | |
| "name": "Alice", | |
| "friendName": "Bob", | |
| }, | |
| } | |
| // 执行查询 | |
| ctx := context.Background() | |
| err = pool.QueryWithRetry(ctx, queries, params, 3) | |
| if err != nil { | |
| log.Printf("Failed to execute queries: %v", err) | |
| return | |
| } | |
| log.Println("Queries executed successfully") | |
| } | |
| // 使用示例:批量创建用户和关系 | |
| func createUsersAndRelationships(pool *Neo4jPool, users []map[string]interface{}) error { | |
| queries := make([]string, 0, len(users)*2) | |
| params := make([]map[string]interface{}, 0, len(users)*2) | |
| for _, user := range users { | |
| // 创建用户节点 | |
| queries = append(queries, "CREATE (u:User {name: $name, age: $age})") | |
| params = append(params, map[string]interface{}{ | |
| "name": user["name"], | |
| "age": user["age"], | |
| }) | |
| // 创建关系 | |
| if friendName, ok := user["friend"].(string); ok { | |
| queries = append(queries, "MATCH (u:User {name: $name}) CREATE (u)-[:FOLLOWS]->(f:User {name: $friendName})") | |
| params = append(params, map[string]interface{}{ | |
| "name": user["name"], | |
| "friendName": friendName, | |
| }) | |
| } | |
| } | |
| return pool.QueryWithRetry(context.Background(), queries, params, 3) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| go get Neo4j | |
| go run main.go |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment