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 文件,内容大致如下:

复制代码
module myproject
go 1.18

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

复制代码
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 执行、预备语句、类型映射、超时控制等实战内容。

相关推荐
Tairitsu_H1 分钟前
[C++] C++11 Lambda与包装器深度解析
开发语言·c++·c++11·lambda·包装器
liangsheng_g4 分钟前
Spring事务传播行为分派与挂起恢复源码实战
数据库·sql·spring
傲世仙尊9 分钟前
从磁盘硬件到Ext文件系统-Linux磁盘级文件系统学习笔记
linux·运维·服务器·开发语言·c++
蓝速科技18 分钟前
信创终端 POC 测试实战与选型避坑指南丨蓝速科技
运维·数据库·人工智能·科技·自然语言处理
小羊没烦恼!28 分钟前
Memory 记忆设计讨论:为什么 Agent Memory 不能只靠向量数据库?
java·开发语言·windows·算法·c#
风哥2号33 分钟前
数据库教程FGMT29‑Linux平台MySQL5.7安装配置与管理入门
数据库
黑马程序员毕设43 分钟前
基于微信小程序的节目活动报名与管理系统设计与实现
java·开发语言·spring boot·后端·电脑
sunshine22 girl1 小时前
Java学习 java原理
java·开发语言·学习
杨云龙UP1 小时前
MySQL Host is blocked because of many connection errors 导致 JDBC 连接失败排查与解决
linux·运维·网络·数据库·sql·mysql·登录失败
troy1282 小时前
Python 基础语法(六):函数与模块、文件操作、异常处理
开发语言·python