Go語(yǔ)言操作金倉(cāng)數(shù)據(jù)庫(kù)的環(huán)境搭建與連接管理
從一個(gè)實(shí)際問(wèn)題說(shuō)起
去年寫(xiě)一個(gè)數(shù)據(jù)采集服務(wù),用 Go 語(yǔ)言開(kāi)發(fā),需要連金倉(cāng)數(shù)據(jù)庫(kù)。項(xiàng)目工期緊,心想 Go 的標(biāo)準(zhǔn)庫(kù) database/sql 應(yīng)該能直接支持吧?結(jié)果一查,發(fā)現(xiàn)金倉(cāng)的 Go 驅(qū)動(dòng)需要單獨(dú)配置,而且網(wǎng)上資料不多。
折騰了一天多才跑通。今天把過(guò)程整理出來(lái),分成上下兩篇。上篇講環(huán)境搭建和連接管理,下篇講 SQL 執(zhí)行和高級(jí)特性。
一、Gokb 驅(qū)動(dòng)是什么
Gokb 是金倉(cāng)官方提供的 Go 語(yǔ)言驅(qū)動(dòng),完全用 Go 編寫(xiě),實(shí)現(xiàn)了 database/sql 接口。這意味著你只需要導(dǎo)入這個(gè)驅(qū)動(dòng),剩下的操作都用 Go 標(biāo)準(zhǔn)庫(kù)的方式寫(xiě)就行。
驅(qū)動(dòng)的特點(diǎn):
- 純 Go 實(shí)現(xiàn),沒(méi)有 CGO 依賴
- 支持
database/sql標(biāo)準(zhǔn)接口 - 支持連接池、預(yù)備語(yǔ)句、事務(wù)等常用功能
- 支持多主機(jī)高可用配置
官方推薦直接使用 database/sql 包,不直接調(diào)用驅(qū)動(dòng)內(nèi)部接口。
二、環(huán)境搭建
2.1 安裝 Go
首先得把 Go 環(huán)境裝好。去 Go 官網(wǎng)下載對(duì)應(yīng)操作系統(tǒng)的安裝包。
Linux 下安裝:
# 解壓 tar -zxvf go1.20.linux-amd64.tar.gz # 配置環(huán)境變量 export PATH=/path/to/go/bin:$PATH # 驗(yàn)證 go version
2.2 兩種包管理方式
Gokb 支持 GOPATH 和 Go Module 兩種方式。推薦用 Go Module,更現(xiàn)代。
方式一:Go Module(推薦)
先初始化項(xiàng)目:
go mod init myproject
項(xiàng)目根目錄會(huì)生成 go.mod 文件,內(nèi)容大致如下:
module myproject go 1.18
把解壓后的 Gokb 驅(qū)動(dòng)源碼放到任意目錄,比如 ./gokb/。然后在 go.mod 中添加 replace 指令:
module myproject go 1.18 require kingbase.com/gokb v1.0.0 replace kingbase.com/gokb => ./gokb
最后拉取依賴:
go mod tidy
這個(gè)命令會(huì)自動(dòng)下載 Gokb 依賴的其他包(比如 decimal、civil 等)。
方式二:GOPATH
需要先把 GO111MODULE 關(guān)了:
export GO111MODULE=off
然后把 Gokb 源碼放到 $GOPATH/src/kingbase.com/gokb 目錄下。手動(dòng)下載依賴包并拷貝到 $GOPATH/src。
我建議用第一種,省事。
2.3 導(dǎo)入驅(qū)動(dòng)
在代碼中通過(guò) _ 方式導(dǎo)入驅(qū)動(dòng),這樣驅(qū)動(dòng)會(huì)自動(dòng)注冊(cè)到 database/sql:
import (
"database/sql"
_ "kingbase.com/gokb" // 匿名導(dǎo)入,只執(zhí)行 init 函數(shù)
)三、連接數(shù)據(jù)庫(kù)
3.1 基本連接
和其他語(yǔ)言不同,sql.Open 不會(huì)立即建立連接,它只是解析連接串、創(chuàng)建 db 對(duì)象。真正連接是在第一次使用時(shí)建立的。
所以 Open 之后要調(diào)用 Ping 驗(yàn)證連接是否成功。
package main
import (
"database/sql"
"fmt"
_ "kingbase.com/gokb"
)
const (
host = "127.0.0.1"
port = 54321
user = "system"
password = "123456"
dbname = "TEST"
)
func main() {
connStr := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
db, err := sql.Open("kingbase", connStr)
if err != nil {
panic(err)
}
defer db.Close()
// 重要:驗(yàn)證連接是否成功
err = db.Ping()
if err != nil {
panic(err)
}
fmt.Println("連接成功!")
}3.2 連接參數(shù)詳解
連接字符串是鍵值對(duì)格式,空格分隔。常用參數(shù):
| 參數(shù) | 說(shuō)明 | 默認(rèn)值 |
|---|---|---|
| host | 服務(wù)器地址 | localhost |
| port | 端口 | 54321 |
| user | 用戶名 | 無(wú) |
| password | 密碼 | 無(wú) |
| dbname | 數(shù)據(jù)庫(kù)名 | 同用戶名 |
| sslmode | SSL模式 | require |
| connect_timeout | 連接超時(shí)(秒) | 0(無(wú)限) |
| keepalive_interval | ?;钐綔y(cè)間隔(秒) | 15 |
如果參數(shù)值包含空格,用單引號(hào)括起來(lái):
// 用戶名是 "space man" connStr := `user='space man' password='it''s valid' dbname=TEST`
3.3 多主機(jī)配置
生產(chǎn)環(huán)境通常是集群部署,可以配置多個(gè)主機(jī)實(shí)現(xiàn)故障轉(zhuǎn)移:
// 兩個(gè)主機(jī)不同端口 connStr := "host=192.168.1.100,192.168.1.101 port=54321,54322 user=system password=123456 dbname=TEST" // 兩個(gè)主機(jī)同端口 connStr := "host=192.168.1.100,192.168.1.101 port=54321 user=system password=123456 dbname=TEST"
也可以配合重試參數(shù):
connStr := "host=192.168.1.100,192.168.1.101 port=54321 user=system password=123456 dbname=TEST retry=3 delay=2"
retry=3 表示一輪所有主機(jī)都失敗后,再重新嘗試 3 次。delay=2 表示每次重試前等待 2 秒。
3.4 只連主節(jié)點(diǎn)
如果只想連接主節(jié)點(diǎn)(讀寫(xiě)節(jié)點(diǎn)),配置 target_session_attrs=read-write:
connStr := "host=192.168.1.100,192.168.1.101 port=54321 user=system password=123456 dbname=TEST target_session_attrs=read-write"
驅(qū)動(dòng)會(huì)依次嘗試每個(gè)主機(jī),直到連到一個(gè)支持讀寫(xiě)的主節(jié)點(diǎn)。
3.5 SSL 配置
// 禁用 SSL connStr := "host=127.0.0.1 user=system password=123456 dbname=TEST sslmode=disable" // 開(kāi)啟 SSL connStr := "host=127.0.0.1 user=system password=123456 dbname=TEST sslmode=require" // 使用證書(shū) connStr := "host=127.0.0.1 user=system password=123456 dbname=TEST sslmode=verify-full sslcert=client.crt sslkey=client.key sslrootcert=ca.crt"
四、連接池管理
Go 的 database/sql 自帶連接池,不用第三方庫(kù)。但默認(rèn)參數(shù)需要根據(jù)業(yè)務(wù)調(diào)整。
4.1 連接池參數(shù)
// 設(shè)置最大打開(kāi)連接數(shù)(默認(rèn)無(wú)限) db.SetMaxOpenConns(20) // 設(shè)置最大空閑連接數(shù)(默認(rèn)2) db.SetMaxIdleConns(10) // 設(shè)置連接最大存活時(shí)間 db.SetConnMaxLifetime(time.Hour) // 設(shè)置空閑連接最大存活時(shí)間 db.SetConnMaxIdleTime(10 * time.Minute)
生產(chǎn)環(huán)境建議配置這些參數(shù),避免連接數(shù)過(guò)高導(dǎo)致數(shù)據(jù)庫(kù)壓力大。
4.2 連接池行為說(shuō)明
db 對(duì)象代表一個(gè)連接池,可以被多個(gè) goroutine 安全地并發(fā)使用。Go 會(huì)自動(dòng)管理連接的創(chuàng)建和回收。
有兩個(gè)特殊情況需要注意:
- 調(diào)用
Begin()開(kāi)啟事務(wù)后,返回的Tx對(duì)象會(huì)綁定到單個(gè)連接,直到Commit()或Rollback()后才釋放。 - 調(diào)用
Query()返回的Rows對(duì)象也會(huì)占用連接,需要用defer rows.Close()釋放。
// 正確寫(xiě)法:用 defer 確保釋放
rows, err := db.Query("SELECT * FROM users")
if err != nil {
return err
}
defer rows.Close() // 重要!
for rows.Next() {
// 處理數(shù)據(jù)
}4.3 關(guān)閉連接
db.Close()
但 db 對(duì)象是為長(zhǎng)連接設(shè)計(jì)的,不要頻繁 Open 和 Close。通常程序啟動(dòng)時(shí) Open 一次,程序退出時(shí) Close。
五、完整示例
下面是一個(gè)完整的連接示例,包含了連接池配置:
package main
import (
"database/sql"
"fmt"
"time"
_ "kingbase.com/gokb"
)
const (
host = "127.0.0.1"
port = 54321
user = "system"
password = "123456"
dbname = "TEST"
)
func main() {
connStr := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable connect_timeout=10",
host, port, user, password, dbname)
db, err := sql.Open("kingbase", connStr)
if err != nil {
panic(fmt.Sprintf("打開(kāi)數(shù)據(jù)庫(kù)失敗: %v", err))
}
defer db.Close()
// 配置連接池
db.SetMaxOpenConns(10)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(time.Hour)
db.SetConnMaxIdleTime(10 * time.Minute)
// 驗(yàn)證連接
err = db.Ping()
if err != nil {
panic(fmt.Sprintf("連接數(shù)據(jù)庫(kù)失敗: %v", err))
}
fmt.Println("連接成功!")
fmt.Printf("連接池狀態(tài): MaxOpen=%d, MaxIdle=%d\n", db.Stats().MaxOpenConnections, db.Stats().Idle)
}六、常見(jiàn)問(wèn)題
6.1 驅(qū)動(dòng)注冊(cè)失敗
報(bào)錯(cuò) driver: unknown driver "kingbase",說(shuō)明驅(qū)動(dòng)沒(méi)注冊(cè)成功。檢查是否正確導(dǎo)入了 _ "kingbase.com/gokb"。
6.2 連接超時(shí)
可以設(shè)置 connect_timeout 參數(shù):
connStr := "host=127.0.0.1 user=system password=123456 dbname=TEST connect_timeout=10"
6.3 連接斷開(kāi)后無(wú)法自動(dòng)重連
Go 的連接池默認(rèn)不會(huì)自動(dòng)重連??梢杂?SetConnMaxLifetime 定期回收連接,或者用 ping 檢測(cè):
// 定期 ping 檢測(cè)連接是否正常
go func() {
ticker := time.NewTicker(30 * time.Second)
for range ticker.C {
if err := db.Ping(); err != nil {
log.Printf("ping 失敗: %v", err)
}
}
}()七、小結(jié)
上篇主要講了:
- 環(huán)境搭建:Gokb 驅(qū)動(dòng)安裝、Go Module 配置、驅(qū)動(dòng)導(dǎo)入
- 連接數(shù)據(jù)庫(kù):連接字符串格式、參數(shù)說(shuō)明、多主機(jī)配置
- 連接池管理:參數(shù)設(shè)置、行為說(shuō)明、事務(wù)和 Rows 的特殊處理
到此這篇關(guān)于Go語(yǔ)言操作金倉(cāng)數(shù)據(jù)庫(kù)的環(huán)境搭建與連接管理的文章就介紹到這了,更多相關(guān)Go語(yǔ)言操作金倉(cāng)數(shù)據(jù)庫(kù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go 使用Unmarshal將json賦給struct出錯(cuò)的原因及解決
這篇文章主要介紹了Go 使用Unmarshal將json賦給struct出錯(cuò)的原因及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03
Go語(yǔ)言實(shí)戰(zhàn)之切片內(nèi)存優(yōu)化
Go 語(yǔ)言的切片是一個(gè)動(dòng)態(tài)的數(shù)據(jù)結(jié)構(gòu),可以方便地對(duì)其進(jìn)行擴(kuò)容和縮容操作。這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言如何實(shí)現(xiàn)切片內(nèi)存優(yōu)化,需要的可以參考一下2023-03-03
go代碼實(shí)現(xiàn)買房貸款月供計(jì)算的方法
今天小編就為大家分享一篇關(guān)于go代碼實(shí)現(xiàn)買房貸款月供計(jì)算的方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-04-04
Go語(yǔ)言實(shí)現(xiàn)并發(fā)控制的常見(jiàn)方式詳解
這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言實(shí)現(xiàn)并發(fā)控制的幾種常見(jiàn)方式,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考一下2024-03-03
go語(yǔ)言中空結(jié)構(gòu)體的實(shí)現(xiàn)
本文主要介紹了go語(yǔ)言中空結(jié)構(gòu)體的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-04-04
用gin開(kāi)發(fā)的golang項(xiàng)目三種開(kāi)發(fā)模式方式
這篇文章主要介紹了用gin開(kāi)發(fā)的golang項(xiàng)目三種開(kāi)發(fā)模式方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01

