#前面已經分享過以 HTTP API 或 JavaScript driver 開發 Neo4j 前端應用,今天我們就來看後端應用囉,這篇文章會以 Golang 語言為參考。
目前(2020/10) Neo4j 官方支援的程式語言有 Java、 .NET、JavaScript、Python、Go,針對 Java 還有額外支援框架 Spring、Neo4j-OGM。
其他語言如 Ruby、PHP、Erlang/Elixir、Perl、C/C++、Clojure、Haskell、R 則都是 Neo4j 社區中的開發者們所貢獻,但也都有收錄在官方教學
使用 go get 或 GO Module 管理 package,建議後者。
go get github.com/neo4j/neo4j-go-driver/neo4j
go mod init github.com/eggttball/go-neo4j
go mod edit -require github.com/neo4j/neo4j-go-driver@v1.8.3
Import neo4j driver
import "github.com/neo4j/neo4j-go-driver/neo4j"
連線 Neo4j 資料庫服務的第一個步驟,便是宣告 driver
物件,一個應用程式只需要初始化這樣一個物件即可,勿初始化多個 driver,並在程式結束後手動關閉,一個 driver 會維護一個 Connection Pool 來自動管理資料庫的連線與釋放。
以下的範例程式碼在初始化 Session 後立即關閉 driver,只是示範關閉 driver,實務應用上,勿頻繁地關閉 driver 並重新初始化 driver。
session
物件則是管理一連串交易的容器,如果你寫多執行緒的應用,不需要擔心 driver 物件的狀態不同步;但是 session 物件就必須注意其狀態,不可以執行緒共用,並應在完成交易後立即關閉。
create driver and session
driver, err := neo4j.NewDriver("bolt://localhost:7687", neo4j.BasicAuth("neo4j", password, ""), func(c *neo4j.Config) {
c.Encrypted = encrypted
})
if err != nil {
return "", err
}
defer driver.Close()
session, err := driver.Session(neo4j.AccessModeWrite)
if err != nil {
return "", err
}
defer session.Close()
這邊指定的 Access Mode Read/Write 有助於在連線因果叢集時,讓叢集決定要將 Cypher 查詢指派給 Core server 還是 Replica server,正確的設定 Access Mode 將有助於資料庫的效能大幅提升。
不過在 Session 初始化時的 Access Mode 只會影響自動交易,如果是手動交易,Access Mode 最終還是取決於 Session.WriteTransaction 或是 Session.ReadTransaction。
Session.Run
就相當於 HTTP API 的 /tx/commit,在單次的資料庫要求開啟交易並立即確認執行。
Result.Consume 會一次讀取所有的回傳資料並回傳 Summary
result, err := session.Run("CREATE (a:Person {name: $name})", map[string]interface{}{"name":
name})
if err != nil {
return err
}
if _, err = result.Consume(); err != nil {
return err
}
greeting, err := session.WriteTransaction(func(transaction neo4j.Transaction) (interface{}, error) {
result, err := transaction.Run(
"CREATE (a:Greeting) SET a.message = $message RETURN a.message + ', from node ' + id(a)",
map[string]interface{}{"message": "hello, world"})
if err != nil {
return nil, err
}
if result.Next() {
return result.Record().GetByIndex(0), nil
}
return nil, result.Err()
})
這邊用到了 Result.Next() 來確認是否有回傳結果,以及 Result.Record() 來取得每一筆資料
如果預期回傳的資料有多筆,可以這樣寫。
for result.Next() {
record = result.Record();
if value, ok := record.Get('field_name'); ok {
// a value with alias field_name was found
// process value
}
}
以上也刻意示範了 Get by index 和 Get by field name 的選擇作法
從資料庫取得的結果都會是 interface{} 型別,在程式碼中的操作很不便,但我們可以把它 UnBoxing 成真正的物件型別,列表如下
Cypher Type | Driver Type |
---|---|
null | nil |
List | []interface{} |
Map | map[string]interface{} |
Boolean | bool |
Integer | int64 |
Float | float |
String | string |
ByteArray | []byte |
Node | neo4j.Node |
Relationship | neo4j.Relationship |
Path | neo4j.Path |
Point | neo4j.Point |
Date | neo4j.Date |
Time | neo4j.OffsetTime |
LocalTime | neo4j.LocalTime |
DateTime | time.Time |
LocalDateTime | neo4j.LocalDateTime |
Duration | neo4j.Duration |
例如
value, ok := record.Get('birthday').(neo4j.Date)
如果資料庫是採用因果叢集架構,只需要將協定改成 bolt+routing 中可,後面接的機器位址則必須是任一台 Core Server。
if driver, err = neo4j.NewDriver("bolt+routing://localhost:7687", neo4j.BasicAuth("username", "password", "")); err != nil {
return err
}
資考資源:
https://github.com/neo4j/neo4j-go-driver
https://neo4j.com/docs/pdf/neo4j-driver-manual-1.7-go.pdf
https://godoc.org/github.com/neo4j/neo4j-go-driver/neo4j