You need to enable JavaScript to run this app.
导航
MySQL Go Driver
最近更新时间:2025.10.22 19:18:53首次发布时间:2024.08.01 20:24:07
复制全文
我的收藏
有用
有用
无用
无用

本文介绍如何在 Go 开发环境连接并访问 ByteHouse 云数仓。

环境要求

驱动

已验证版本

Mysql Go 驱动

1.8.1+,驱动下载链接

Go

Golang 1.20+

使用限制
  • 不支持 ByteHouse 的 JSONB 和 Bitmap64 的数据类型。
  • 当前 ByteHouse MySQL 协议不支持 ComPrepare 协议,因此 insert batch 逻辑无法使用 MySQL Go 中的 prepare,只能拼接 SQL。
  • 当前不支持数据库账号的认证。
  • 不支持设置 query ID。
  • 不支持在连接层面(sql.Open)设置计算组。
  • 如果您在使用过程中遇到其他未知限制,请联系 ByteHouse 团队处理。

安装依赖程序

您可以在 程序Github 主页 获取最新的文档和发布版本信息。

go get -u github.com/go-sql-driver/mysql

-- 以下为依赖程序
go get -u github.com/stretchr/testify

安装完成后,在 Go 程序代码的 import 中插入以下内容。

import (
        "database/sql"

        _ "github.com/go-sql-driver/mysql"
)

获取 ByteHouse 连接信息

ByteHouse 支持通过 IAM 用户连接,所需连接信息获取方式如下。更多连接操作请参考步骤三:获取 ByteHouse 连接串信息

参数

配置说明

host

配置为 ByteHouse 的公网/私网域名,您可以在 ByteHouse 控制台的租户管理 > 基本信息 > 网络信息中查看并复制网络信息。详情请参见步骤二:配置网络信息

port

配置为固定值 3306。

user & password

使用 API Key 作为 user 和 password。详情请参见获取 API Key

  • user:为 API Key 的前半部分,比如获取的 API Key 为 xxxx.yyyy,则 User 需填写 xxxx
  • password:为 API Key 的前半部分,比如获取的 API Key 为 xxxx.yyyy,则 User 需填写 yyyy

database

配置为连接 ByteHouse 的数据库名称。

基本用法

您可以使用以下代码连接至 ByteHouse,并开始使用标准语句开发 ByteHouse,用于查询、写入和读取数据。

  • 超时时间配置:timeout 默认为 0s、readTimeout 默认为 0s、writeTimeout 默认为 0s。
  • 默认支持 keepAlive,可以复用连接和避免短链接。

连接至 ByteHouse

可参考下面代码样例填写 ByteHouse 连接信息,注意根据中获取的信息填写其中的 {Host}{Password}{User}{Database}{VIRTUAL_WAREHOUSE_ID} 等字段的值,获取方式请参见获取 ByteHouse 连接信息

host := "{Host}"
port := 3306
password := "{Password}"
user := "{User}"
database := "{Database}"
virtual_warehouse_id := "{VIRTUAL_WAREHOUSE_ID}"

db, err := sql.Open(
   "mysql", 
   fmt.Sprintf("%v:%v@(%v:%v)/%v", user, password, host, port, database),
)
if err != nil {
   log.Fatal(err)
}

设置特定计算组(连接级别)

通过创建每一个连接(connection)后设置计算组配置。

_, err = conn.ExecContext(ctx, fmt.Sprintf("set virtual_warehouse = '%v'", virtual_warehouse_id))
    if err != nil {
        log.Fatal(err)
    }

基本用法示例

package main

import (
    "context"
    "database/sql"
    "fmt"
    "github.com/go-sql-driver/mysql"
    _ "github.com/go-sql-driver/mysql"
    "github.com/google/uuid"
    "log"
    "strconv"
    "strings"
    "time"
)

func main() {
    host := "{Host}"
    port := 3306
    password := "{Password}"
    user := "{User}"
    database := "{Database}"
    virtual_warehouse_id := "{VIRTUAL_WAREHOUSE_ID}"

    db, err := sql.Open(
       "mysql", 
       fmt.Sprintf("%v:%v@(%v:%v)/%v", user, password, host, port, database),
    )
    if err != nil {
       log.Fatal(err)
    }

    if err := db.Ping(); err != nil {
       log.Fatal(err)
    }
    ctx := context.Background()
    conn, err := db.Conn(context.Background())
    if err != nil {
       log.Fatal(err)
    }
    defer conn.Close()
    defer db.Close()
    
    _, err = conn.ExecContext(ctx, fmt.Sprintf("set virtual_warehouse = '%v'", virtual_warehouse_id))
    if err != nil {
        log.Fatal(err)
    }
    
    _, err = conn.ExecContext(ctx, "DROP DATABASE IF EXISTS bhgotest")
    if err != nil {
       log.Fatal(err)
    }

    _, err = conn.ExecContext(ctx, "CREATE DATABASE IF NOT EXISTS bhgotest")
    if err != nil {
       log.Fatal(err)
    }

    _, err = conn.ExecContext(ctx, `
CREATE TABLE IF NOT EXISTS bhgotest.example (
        Col1 UInt8
    , Col2 String
    , Col3 FixedString(3)
    , Col4 UUID
    , Col5 Map(String, UInt8)
    , Col6 Array(String)
    , Col7 Tuple(String, UInt8, Array(Map(String, String))) KV
    , Col8 DateTime
) Engine = CnchMergeTree() ORDER BY tuple()
`)
    if err != nil {
       log.Fatal(err)
    }

    values_list := make([]string, 0)
    for i := 0; i < 1000; i++ {
       value := fmt.Sprintf("(%v,%v,%v,'%v',%v,%v,%v,'%v')", uint8(42),
          "'ClickHouse'", "'Inc'",
          uuid.New(),
          "{'key': 1}",                     // Map(String, UInt8)
          "['Q', 'W', 'E', 'R', 'T', 'Y']", // Array(String)
          "('String Value', 5, [{'key': 'value'},{'key': 'value'},{'key': 'value'}])",
          time.Now().Format("2006-01-02 15:04:05"))
       values_list = append(values_list, value)
    }

    sql := fmt.Sprintf("INSERT INTO bhgotest.example VALUES %s",
       strings.Join(values_list, ", "))
    _, err = conn.ExecContext(ctx, sql)
    if err != nil {
       log.Fatal(err)
    }

    row := conn.QueryRowContext(ctx, "SELECT * FROM bhgotest.example  limit 1")
    var (
       col1             uint8
       col2, col3, col4 string
       col5             string
       col6             string
       col7             string
       col8             string
    )
    if err := row.Scan(&col1, &col2, &col3, &col4, &col5, &col6, &col7, &col8); err != nil {
       log.Fatal(err)
    }
    print(col1, col2, col3, col4, col5, col6, col7, col8)

    conn.ExecContext(ctx, "DROP TABLE IF EXISTS bhgotest.example")

}