clickhouse v2 驱动不支持 sql.open,必须用 clickhouse.open(&clickhouse.options{}) 获取原生连接;dsn 必须为 tcp://127.0.0.1:9000 格式,http 端口 8123 不可用;批量插入需用 preparebatch + send,scanstruct 要求 ch tag 严格匹配列名。

clickhouse.Open 不能替换成 sql.Open
用 sql.Open("clickhouse", dsn) 必 panic,v2 驱动压根没注册到 database/sql 接口。Gin 路由里写数据库逻辑时,必须直接调 clickhouse.Open(&clickhouse.Options{}) 获取原生连接对象。
常见错误现象:sql: unknown driver "clickhouse" (forgotten import?) —— 不是漏 import,是驱动根本不支持该接口。
-
Addr必须是[]string{"127.0.0.1:9000"},传单个 string 会编译失败 - 若在 Gin 的
main()或中间件中初始化连接,记得把conn存到gin.Context或全局变量,别每次请求都重连 - 连接池由
clickhouse.Options中的MaxOpenConns和MaxIdleConns控制,不是sql.DB那套
HTTP 端口 8123 在 v2 驱动里基本不可用
v2 驱动只认 TCP 协议(Native interface),http://127.0.0.1:8123 这类 DSN 会被静默忽略或报 dial timeout。本地开发连不上?八成是服务端只开了 HTTP,但客户端硬要走 TCP。
正确做法:
- 确认服务端
config.xml中<tcp_port>9000</tcp_port>已启用(默认开) - DSN 写成
tcp://127.0.0.1:9000?database=default&secure=false&compress=false - 若服务端强制 TLS(如 ClickHouse Cloud),则
secure=true且需配TLSConfig,否则卡在 handshake
INSERT 百万行不卡死的关键:PrepareBatch + Send
Gin 接口接收 JSON 批量上报日志,想存 ClickHouse?别循环 conn.Exec("INSERT ..."),10 万行可能耗时 30 秒以上,还容易 OOM。
实操要点:
- 用
conn.PrepareBatch("INSERT INTO events (ts, user_id, action) VALUES (?, ?, ?)")拿 batch 实例 - 每批控制在 10000–100000 行;太小吞吐低,太大触发
max_insert_block_size拒绝 -
batch.Append(ts, userID, action)只是内存攒数,漏掉batch.Send()就等于没发 - 写入前统一转 UTC:
ts.UTC(),避免时区错位导致后续 GROUP BY 失效
ScanStruct 字段为零值却不报错?ch tag 拼错了
Gin 返回 JSON 时结构体字段全为零值,rows.ScanStruct(&event) 却不 panic、不 warn —— 八成是 ch 标签大小写或下划线对不上。
ClickHouse 列名是 user_id,结构体必须写:
type Event struct {
UserID int64 `ch:"user_id"`
Action string `ch:"action"`
}
以下写法都会静默失败,字段保持零值:
-
`ch:"User_id"`(大小写错) -
`ch:"user_id "`(尾部空格) -
`json:"user_id"`(用 json tag,ch 标签不识别) `ch:"user_id"` 但列实际叫 <code>u_id(建表名和 tag 不一致)
Nullable 字段如 Nullable(String),必须用 ch.String 或 sql.NullString,*string 直接 panic。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











