--- sidebar_position: 4 sidebar_label: Go title: Go Connector --- import Preparition from "./_preparition.mdx" ## 总体介绍 driver-go 是 TDengine 的官方 Go 语言连接器。Go 语言开发人员可以通过它开发存取 TDengine 数据库的应用软件。driver-go 实现了 Go [database/sql](https://golang.org/pkg/database/sql/) 包的接口,支持通过客户端驱动程序(taosc)原生连接 TDengine 服务端,支持数据写入、查询、订阅、schemaless 接口和参数绑定接口等功能。 driver-go 也支持使用 REST 连接 TDengine 服务端。 本文介绍如何在 Windows 或 Linux 环境中安装 driver-go,并通过 driver-go 连接 TDengine 数据库、进行数据查询、数据写入等基本操作。 Go 连接器的源码托管在 github。项目名称:driver-go。欢迎 [贡献源码](https://github.com/taosdata/driver-go) 或 [报告问题](https://github.com/taosdata/driver-go/issues)。 ## 支持的平台 | **CPU 类型** | x64(64bit) | | | aarch64 | aarch32 | |------------|------------|--------|--------|---------|---------| | **OS 类型** | Linux | Win64 | Win32 | Linux | Linux | | **支持与否** | **支持** | **支持** | **支持** | **支持** | **支持** | ## 版本支持 | 分支 | 功能 | 建议 taosd 版本 | |:-------:|:---------------------------------------------:|:-----------:| | master | database/sql(cgo)、订阅、schemaless写入、stmt | 2.2.0.0 及以上 | | develop | database/sql(cgo & REST)、订阅、schemaless写入、stmt | 2.4.0.4及以上 | ## 支持的特性 ### 原生连接 “原生连接”指连接器通过客户端驱动(taosc)直接与 TDengine 服务端建立连接。 * database/sql (cgo 模式) * 订阅 * schemaless 接口 * 参数绑定接口 ### REST 连接 REST 连接指连接器通过 taosAdapter 组件提供的 REST API 建立与 taosd 的连接。 `develop` 分支使用 `http client` 实现了 `database/sql` 接口。 ## 安装步骤 ### 安装前的准备 1. 安装 Go 开发环境(Go 1.14 及以上,GCC 4.8.5 及以上) 配置好环境变量,检查命令: * ```go env``` * ```gcc -v``` ### 使用 go get 安装 `go get -u github.com/taosdata/driver-go/v2@develop` ## 建立连接 ### DSN 数据源名称具有通用格式,例如 [PEAR DB](http://pear.php.net/manual/en/package.database.db.intro-dsn.php),但没有类型前缀(方括号表示可选): ``` text [username[:password]@][protocol[(address)]]/[dbname][?param1=value1&...¶mN=valueN] ``` 完整形式的 DSN: ```text username:password@protocol(address)/dbname?param=value ``` ### 建立原生连接 _taosSql_ 通过 cgo 实现了 Go 的 `database/sql/driver` 接口。只需要引入驱动就可以使用[`database/sql`](https://golang.org/pkg/database/sql/)的接口。 使用 `taosSql` 作为 `driverName` 并且使用一个正确的 [DSN](#DSN) 作为 `dataSourceName`,DSN 支持的参数: * configPath 指定 taos.cfg 目录 示例: ```go package main import ( "database/sql" "fmt" _ "github.com/taosdata/driver-go/v2/taosSql" ) func main() { var taosUri = "root:taosdata/tcp(localhost:6030)/" taos, err := sql.Open("taosSql", taosUri) if err != nil { fmt.Println("failed to connect TDengine, err:", err) return } } ``` ### 建立 REST 连接 _taosRestful_ 通过 `http client` 实现了 Go 的 `database/sql/driver` 接口。只需要引入驱动就可以使用[`database/sql`](https://golang.org/pkg/database/sql/)的接口。 使用 `taosRestful` 作为 `driverName` 并且使用一个正确的 [DSN](#DSN) 作为 `dataSourceName`,DSN 支持的参数: * `disableCompression` 是否接受压缩数据,默认为 true 不接受压缩数据,如果传输数据使用 gzip 压缩设置为 false。 * `readBufferSize` 读取数据的缓存区大小默认为 4K(4096),当查询结果数据量多时可以适当调大该值。 示例: ```go package main import ( "database/sql" "fmt" _ "github.com/taosdata/driver-go/v2/taosRestful" ) func main() { var taosUri = "root:taosdata/http(localhost:6041)/" taos, err := sql.Open("taosRestful", taosUri) if err != nil { fmt.Println("failed to connect TDengine, err:", err) return } } ``` ## 示例程序 使用 Go 连接器的示例代码请参考: * [示例程序](https://github.com/taosdata/TDengine/tree/develop/examples/go) * [视频教程](https://www.taosdata.com/blog/2020/11/11/1951.html)。 ### 使用限制 由于 REST 接口无状态所以 `use db` 语法不会生效,需要将 db 名称放到 SQL 语句中,如:`create table if not exists tb1 (ts timestamp, a int)`改为`create table if not exists test.tb1 (ts timestamp, a int)`否则将报错`[0x217] Database not specified or available`。 也可以将 db 名称放到 DSN 中,将 `root:taosdata@http(localhost:6041)/` 改为 `root:taosdata@http(localhost:6041)/test`,此方法在 TDengine 2.4.0.5 版本的 taosAdapter 开始支持。当指定的 db 不存在时执行 `create database` 语句不会报错,而执行针对该 db 的其他查询或写入操作会报错。 完整示例如下: ```go package main import ( "database/sql" "fmt" "time" _ "github.com/taosdata/driver-go/v2/taosRestful" ) func main() { var taosDSN = "root:taosdata@http(localhost:6041)/test" taos, err := sql.Open("taosRestful", taosDSN) if err != nil { fmt.Println("failed to connect TDengine, err:", err) return } defer taos.Close() taos.Exec("create database if not exists test") taos.Exec("create table if not exists tb1 (ts timestamp, a int)") _, err = taos.Exec("insert into tb1 values(now, 0)(now+1s,1)(now+2s,2)(now+3s,3)") if err != nil { fmt.Println("failed to insert, err:", err) return } rows, err := taos.Query("select * from tb1") if err != nil { fmt.Println("failed to select from table, err:", err) return } defer rows.Close() for rows.Next() { var r struct { ts time.Time a int } err := rows.Scan(&r.ts, &r.a) if err != nil { fmt.Println("scan error:\n", err) return } fmt.Println(r.ts, r.a) } } ``` ### 常见问题 * 无法找到包 `github.com/taosdata/driver-go/v2/taosRestful` 将 `go.mod` 中 require 块对`github.com/taosdata/driver-go/v2`的引用改为`github.com/taosdata/driver-go/v2 develop`,之后执行 `go mod tidy`。 * database/sql 中 stmt 相关接口崩溃 REST 不支持 stmt 相关接口,建议使用`db.Exec`和`db.Query`。 * 使用 `use db` 语句后执行其他语句报错 `[0x217] Database not specified or available` 在 REST 接口中 SQL 语句的执行无上下文关联,使用 `use db` 语句不会生效,解决办法见上方使用限制章节。 * 使用 taosSql 不报错使用 taosRestful 报错 `[0x217] Database not specified or available` 因为 REST 接口无状态,使用 `use db` 语句不会生效,解决办法见上方使用限制章节。 * 升级 `github.com/taosdata/driver-go/v2/taosRestful` 将 `go.mod` 文件中对 `github.com/taosdata/driver-go/v2` 的引用改为 `github.com/taosdata/driver-go/v2 develop`,之后执行 `go mod tidy`。 * `readBufferSize` 参数调大后无明显效果 `readBufferSize` 调大后会减少获取结果时 `syscall` 的调用。如果查询结果的数据量不大,修改该参数不会带来明显提升,如果该参数修改过大,瓶颈会在解析 JSON 数据。如果需要优化查询速度,需要根据实际情况调整该值来达到查询效果最优。 * `disableCompression` 参数设置为 `false` 时查询效率降低 当 `disableCompression` 参数设置为 `false` 时查询结果会使用 `gzip` 压缩后传输,拿到数据后要先进行 `gzip` 解压。 * `go get` 命令无法获取包,或者获取包超时 设置 Go 代理 `go env -w GOPROXY=https://goproxy.cn,direct`。 ## API 全部 API 见 [driver-go 文档](https://pkg.go.dev/github.com/taosdata/driver-go/v2) ### 常用 API #### `database/sql` * `sql.Open(DRIVER_NAME string, dataSourceName string) *DB` 该 API 用来打开 DB,返回一个类型为 \*DB 的对象。 **注意**: 该 API 成功创建的时候,并没有做权限等检查,只有在真正执行 Query 或者 Exec 的时候才能真正的去创建连接,并同时检查 user/password/host/port 是不是合法。 * `func (db *DB) Exec(query string, args ...interface{}) (Result, error)` `sql.Open` 内置的方法,用来执行非查询相关 SQL。 * `func (db *DB) Query(query string, args ...interface{}) (*Rows, error)` `sql.Open` 内置的方法,用来执行查询语句。 #### 高级功能 af 包封装了订阅、stmt 等 TDengine 高级功能。 * `af.Open(host, user, pass, db string, port int) (*Connector, error)` 该 API 通过 cgo 创建与 taosd 的连接。 * `func (conn *Connector) Close() error` 关闭与 taosd 的连接。 * `func (conn *Connector) StmtExecute(sql string, params *param.Param) (res driver.Result, err error)` stmt 单行插入。 * `func (conn *Connector) StmtQuery(sql string, params *param.Param) (rows driver.Rows, err error)` stmt 查询,返回 `database/sql/driver` 包的 `Rows` 结构。 ##### 订阅 * `func (conn *Connector) Subscribe(restart bool, topic string, sql string, interval time.Duration) (Subscriber, error)` 订阅数据。 * `func (s *taosSubscriber) Consume() (driver.Rows, error)` 消费订阅数据,返回 `database/sql/driver` 包的 `Rows` 结构。 * `func (s *taosSubscriber) Unsubscribe(keepProgress bool)` 取消订阅数据。 ##### schemaless 写入 * `func (conn *Connector) InfluxDBInsertLines(lines []string, precision string) error` 写入 influxDB 行协议。 * `func (conn *Connector) OpenTSDBInsertTelnetLines(lines []string) error` 写入 OpenTDSB telnet 协议。 * `func (conn *Connector) OpenTSDBInsertJsonPayload(payload string) error` 写入 OpenTSDB json 协议。 ##### 批量 stmt 插入 * `func (conn *Connector) InsertStmt() *insertstmt.InsertStmt` 初始化 stmt。 * `func (stmt *InsertStmt) Prepare(sql string) error` 预处理 sql 语句。 * `func (stmt *InsertStmt) SetTableName(name string) error` 设置表名。 * `func (stmt *InsertStmt) SetSubTableName(name string) error` 设置子表名。 * `func (stmt *InsertStmt) BindParam(params []*param.Param, bindType *param.ColumnType) error` 绑定多行数据。 * `func (stmt *InsertStmt) AddBatch() error` 添加到批处理。 * `func (stmt *InsertStmt) Execute() error` 执行 stmt。 * `func (stmt *InsertStmt) GetAffectedRows() int` 获取受影响行数。 * `func (stmt *InsertStmt) Close() error` 结束 stmt。