Go 语言操作金仓数据库(上篇):环境搭建与连接管理

Go 语言操作金仓数据库(上篇):环境搭建与连接管理

从一个实际问题说起

去年写一个数据采集服务,用 Go 语言开发,需要连金仓数据库。项目工期紧,心想 Go 的标准库 database/sql 应该能直接支持吧?结果一查,发现金仓的 Go 驱动需要单独配置,而且网上资料不多。

折腾了一天多才跑通。今天把过程整理出来,分成上下两篇。上篇讲环境搭建和连接管理,下篇讲 SQL 执行和高级特性。

一、Gokb 驱动是什么

Gokb 是金仓官方提供的 Go 语言驱动,完全用 Go 编写,实现了 database/sql 接口。这意味着你只需要导入这个驱动,剩下的操作都用 Go 标准库的方式写就行。

驱动的特点:

  • 纯 Go 实现,没有 CGO 依赖
  • 支持 database/sql 标准接口
  • 支持连接池、预备语句、事务等常用功能
  • 支持多主机高可用配置

官方推荐直接使用 database/sql 包,不直接调用驱动内部接口。

二、环境搭建

2.1 安装 Go

首先得把 Go 环境装好。去 Go 官网下载对应操作系统的安装包。

Linux 下安装:

bash 复制代码
# 解压
tar -zxvf go1.20.linux-amd64.tar.gz

# 配置环境变量
export PATH=/path/to/go/bin:$PATH

# 验证
go version

2.2 两种包管理方式

Gokb 支持 GOPATH 和 Go Module 两种方式。推荐用 Go Module,更现代。

方式一:Go Module(推荐)

先初始化项目:

bash 复制代码
go mod init myproject

项目根目录会生成 go.mod 文件,内容大致如下:

arduino 复制代码
module myproject
go 1.18

把解压后的 Gokb 驱动源码放到任意目录,比如 ./gokb/。然后在 go.mod 中添加 replace 指令:

bash 复制代码
module myproject
go 1.18

require kingbase.com/gokb v1.0.0
replace kingbase.com/gokb => ./gokb

最后拉取依赖:

bash 复制代码
go mod tidy

这个命令会自动下载 Gokb 依赖的其他包(比如 decimal、civil 等)。

方式二:GOPATH

需要先把 GO111MODULE 关了:

bash 复制代码
export GO111MODULE=off

然后把 Gokb 源码放到 $GOPATH/src/kingbase.com/gokb 目录下。手动下载依赖包并拷贝到 $GOPATH/src

我建议用第一种,省事。

2.3 导入驱动

在代码中通过 _ 方式导入驱动,这样驱动会自动注册到 database/sql

go 复制代码
import (
    "database/sql"
    _ "kingbase.com/gokb"  // 匿名导入,只执行 init 函数
)

三、连接数据库

3.1 基本连接

和其他语言不同,sql.Open 不会立即建立连接,它只是解析连接串、创建 db 对象。真正连接是在第一次使用时建立的。

所以 Open 之后要调用 Ping 验证连接是否成功。

go 复制代码
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()
    
    // 重要:验证连接是否成功
    err = db.Ping()
    if err != nil {
        panic(err)
    }
    
    fmt.Println("连接成功!")
}

3.2 连接参数详解

连接字符串是键值对格式,空格分隔。常用参数:

参数 说明 默认值
host 服务器地址 localhost
port 端口 54321
user 用户名
password 密码
dbname 数据库名 同用户名
sslmode SSL模式 require
connect_timeout 连接超时(秒) 0(无限)
keepalive_interval 保活探测间隔(秒) 15

如果参数值包含空格,用单引号括起来:

go 复制代码
// 用户名是 "space man"
connStr := `user='space man' password='it''s valid' dbname=TEST`

3.3 多主机配置

生产环境通常是集群部署,可以配置多个主机实现故障转移:

go 复制代码
// 两个主机不同端口
connStr := "host=192.168.1.100,192.168.1.101 port=54321,54322 user=system password=123456 dbname=TEST"

// 两个主机同端口
connStr := "host=192.168.1.100,192.168.1.101 port=54321 user=system password=123456 dbname=TEST"

也可以配合重试参数:

go 复制代码
connStr := "host=192.168.1.100,192.168.1.101 port=54321 user=system password=123456 dbname=TEST retry=3 delay=2"

retry=3 表示一轮所有主机都失败后,再重新尝试 3 次。delay=2 表示每次重试前等待 2 秒。

3.4 只连主节点

如果只想连接主节点(读写节点),配置 target_session_attrs=read-write

go 复制代码
connStr := "host=192.168.1.100,192.168.1.101 port=54321 user=system password=123456 dbname=TEST target_session_attrs=read-write"

驱动会依次尝试每个主机,直到连到一个支持读写的主节点。

3.5 SSL 配置

go 复制代码
// 禁用 SSL
connStr := "host=127.0.0.1 user=system password=123456 dbname=TEST sslmode=disable"

// 开启 SSL
connStr := "host=127.0.0.1 user=system password=123456 dbname=TEST sslmode=require"

// 使用证书
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 自带连接池,不用第三方库。但默认参数需要根据业务调整。

4.1 连接池参数

go 复制代码
// 设置最大打开连接数(默认无限)
db.SetMaxOpenConns(20)

// 设置最大空闲连接数(默认2)
db.SetMaxIdleConns(10)

// 设置连接最大存活时间
db.SetConnMaxLifetime(time.Hour)

// 设置空闲连接最大存活时间
db.SetConnMaxIdleTime(10 * time.Minute)

生产环境建议配置这些参数,避免连接数过高导致数据库压力大。

4.2 连接池行为说明

db 对象代表一个连接池,可以被多个 goroutine 安全地并发使用。Go 会自动管理连接的创建和回收。

有两个特殊情况需要注意:

  1. 调用 Begin() 开启事务后,返回的 Tx 对象会绑定到单个连接,直到 Commit()Rollback() 后才释放。
  2. 调用 Query() 返回的 Rows 对象也会占用连接,需要用 defer rows.Close() 释放。
go 复制代码
// 正确写法:用 defer 确保释放
rows, err := db.Query("SELECT * FROM users")
if err != nil {
    return err
}
defer rows.Close()  // 重要!

for rows.Next() {
    // 处理数据
}

4.3 关闭连接

go 复制代码
db.Close()

db 对象是为长连接设计的,不要频繁 Open 和 Close。通常程序启动时 Open 一次,程序退出时 Close。

五、完整示例

下面是一个完整的连接示例,包含了连接池配置:

go 复制代码
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("打开数据库失败: %v", err))
    }
    defer db.Close()
    
    // 配置连接池
    db.SetMaxOpenConns(10)
    db.SetMaxIdleConns(5)
    db.SetConnMaxLifetime(time.Hour)
    db.SetConnMaxIdleTime(10 * time.Minute)
    
    // 验证连接
    err = db.Ping()
    if err != nil {
        panic(fmt.Sprintf("连接数据库失败: %v", err))
    }
    
    fmt.Println("连接成功!")
    fmt.Printf("连接池状态: MaxOpen=%d, MaxIdle=%d\n", db.Stats().MaxOpenConnections, db.Stats().Idle)
}

六、常见问题

6.1 驱动注册失败

报错 driver: unknown driver "kingbase",说明驱动没注册成功。检查是否正确导入了 _ "kingbase.com/gokb"

6.2 连接超时

可以设置 connect_timeout 参数:

go 复制代码
connStr := "host=127.0.0.1 user=system password=123456 dbname=TEST connect_timeout=10"

6.3 连接断开后无法自动重连

Go 的连接池默认不会自动重连。可以用 SetConnMaxLifetime 定期回收连接,或者用 ping 检测:

go 复制代码
// 定期 ping 检测连接是否正常
go func() {
    ticker := time.NewTicker(30 * time.Second)
    for range ticker.C {
        if err := db.Ping(); err != nil {
            log.Printf("ping 失败: %v", err)
        }
    }
}()

七、小结

上篇主要讲了:

  1. 环境搭建:Gokb 驱动安装、Go Module 配置、驱动导入
  2. 连接数据库:连接字符串格式、参数说明、多主机配置
  3. 连接池管理:参数设置、行为说明、事务和 Rows 的特殊处理

下篇会讲 SQL 执行、预备语句、类型映射、超时控制等实战内容。

相关推荐
codebetter1 小时前
X86 Windows Docker Desktop 运行 arm64 容器
后端
何陋轩1 小时前
Spring AI Function Calling:让AI调用你的Java方法
人工智能·后端·ai编程
alwaysrun1 小时前
Rust之异步框架Tokio
后端·编程语言
Csvn1 小时前
日志系统
后端·python
CodeSheep1 小时前
中国编程第一人,一人抵一城!
前端·后端·程序员
Randyliu1 小时前
20260511-Pydantic和SQLalchemy
后端·python
smallYoung1 小时前
【学习笔记】中间件-RabbitMQ
后端
三千星1 小时前
Java开发者转型AI工程化Week 3:从LangChain4j到AI Agent
后端·langchain