golang Yandex Database原生驱动与database/sql接口插件库ydb-go-sdk的使用

golang Yandex Database原生驱动与database/sql接口插件库ydb-go-sdk的使用

概述

ydb-go-sdk 是一个纯Go实现的YDB原生驱动,同时支持database/sql接口。YDB是一个开源的分布式SQL数据库,结合了高可用性、可扩展性与严格一致性和ACID事务。

支持的Go版本

ydb-go-sdk支持Go官方发布策略支持的所有Go版本,即最新的两个Go版本(或更多,但不保证额外版本的支持)。

安装

go get -u github.com/ydb-platform/ydb-go-sdk/v3

使用示例

连接到YDB

db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
    log.Fatal(err)
}

使用Query服务客户端执行SELECT查询

// 在错误时进行重试操作
err := db.Query().Do( // 在错误时进行重试操作
   ctx, // 上下文管理从Do退出
   func(ctx context.Context, s query.Session) (err error) { // 重试操作
   	streamResult, err := s.Query(ctx, `SELECT 42 as id, "myStr" as myStr;`)
   	if err != nil {
   		return err // 用于驱动自动重试
   	}
   	defer func() { _ = streamResult.Close(ctx) }() // 清理资源
   	for rs, err := range streamResult.ResultSets(ctx) {
   		if err != nil {
   			return err
   		}
   		for row, err := range rs.Rows(ctx) {
   			if err != nil {
   				return err
   			}
   			type myStruct struct {
   				Id  int32  `sql:"id"`
   				Str string `sql:"myStr"`
   			}
   			var s myStruct
   			if err = row.ScanStruct(&s); err != nil {
   				return err // 通常扫描错误不可重试,返回给驱动检查错误
   			}
   		}
   	}

   	return nil
   },
   query.WithIdempotent(),
)
if err != nil {
   log.Fatal(err)
}

使用database/sql接口

import (
    "context"
    "database/sql"
    "log"

    _ "github.com/ydb-platform/ydb-go-sdk/v3"
)

...

db, err := sql.Open("ydb", "grpc://localhost:2136/local")
if err != nil {
    log.Fatal(err)
}
defer db.Close() // 清理资源
var (
    id    int32
    myStr string
)
row := db.QueryRowContext(context.TODO(), `SELECT 42 as id, "my string" as myStr`)
if err = row.Scan(&id, &myStr); err != nil {
    log.Printf("select failed: %v", err)
    return
}
log.Printf("id = %d, myStr = \"%s\"", id, myStr)

认证凭据

驱动提供了几种为YDB创建凭据的方式:

  • ydb.WithAnonymousCredentials() (默认启用,除非另有指定)
  • ydb.WithAccessTokenCredentials("token")
  • ydb.WithStaticCredentials("user", "password")
  • ydb.WithOauth2TokenExchangeCredentials()ydb.WithOauth2TokenExchangeCredentialsFile(configFilePath)
  • 作为连接字符串的一部分,如 grpcs://user:password@endpoint/database

环境变量

ydb-go-sdk支持以下环境变量,这些变量会重新定义驱动的默认行为:

名称 类型 默认值 描述
YDB_SSL_ROOT_CERTIFICATES_FILE string 证书文件路径
YDB_LOG_SEVERITY_LEVEL string quiet 内部驱动日志的严重级别。支持:trace, debug, info, warn, error, fatal, quiet
YDB_LOG_DETAILS string .* 用于查找内部日志记录器的正则表达式
GRPC_GO_LOG_VERBOSITY_LEVEL integer 设置为99以查看grpc日志
GRPC_GO_LOG_SEVERITY_LEVEL string 设置为info以查看grpc日志

更多关于golang Yandex Database原生驱动与database/sql接口插件库ydb-go-sdk的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang Yandex Database原生驱动与database/sql接口插件库ydb-go-sdk的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Yandex Database (YDB) 在 Golang 中的使用

Yandex Database (YDB) 是 Yandex 开发的分布式数据库系统,支持 SQL 查询和 ACID 事务。在 Golang 中,我们可以通过两种方式连接 YDB:

  1. 原生驱动 ydb-go-sdk
  2. 通过 database/sql 接口的标准方式

1. 原生驱动 ydb-go-sdk 使用

安装

go get github.com/ydb-platform/ydb-go-sdk/v3

基本示例

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/ydb-platform/ydb-go-sdk/v3"
	"github.com/ydb-platform/ydb-go-sdk/v3/table"
	"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
	"github.com/ydb-platform/ydb-go-sdk/v3/table/result"
	"github.com/ydb-platform/ydb-go-sdk/v3/table/types"
)

func main() {
	ctx := context.Background()
	
	// 创建连接
	db, err := ydb.Open(ctx,
		"grpcs://ydb.serverless.yandexcloud.net:2135/ru-central1/b1g8skpblkos03malf3s/etn02qso4h3isjb00te1",
		ydb.WithAccessTokenCredentials("your-access-token"),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close(ctx)

	// 创建表
	err = createTable(ctx, db.Table())
	if err != nil {
		log.Fatal(err)
	}

	// 插入数据
	err = upsertData(ctx, db.Table())
	if err != nil {
		log.Fatal(err)
	}

	// 查询数据
	err = selectData(ctx, db.Table())
	if err != nil {
		log.Fatal(err)
	}
}

func createTable(ctx context.Context, c table.Client) error {
	return c.Do(ctx,
		func(ctx context.Context, s table.Session) error {
			return s.CreateTable(ctx, "example",
				options.WithColumn("id", types.TypeUint64),
				options.WithColumn("name", types.TypeUTF8),
				options.WithColumn("created_at", types.TypeTimestamp),
				options.WithPrimaryKeyColumn("id"),
			)
		},
	)
}

func upsertData(ctx context.Context, c table.Client) error {
	return c.Do(ctx,
		func(ctx context.Context, s table.Session) error {
			_, _, err := s.Execute(ctx,
				table.DefaultTxControl(),
				"DECLARE $id AS Uint64; DECLARE $name AS Utf8; DECLARE $created_at AS Timestamp;"+
					"UPSERT INTO example (id, name, created_at) VALUES ($id, $name, $created_at);",
				table.NewQueryParameters(
					table.ValueParam("$id", types.Uint64Value(1)),
					table.ValueParam("$name", types.UTF8Value("Alice")),
					table.ValueParam("$created_at", types.TimestampValueFromTime(time.Now())),
				),
			)
			return err
		},
	)
}

func selectData(ctx context.Context, c table.Client) error {
	return c.Do(ctx,
		func(ctx context.Context, s table.Session) error {
			_, res, err := s.Execute(ctx,
				table.DefaultTxControl(),
				"SELECT id, name, created_at FROM example WHERE id = $id;",
				table.NewQueryParameters(
					table.ValueParam("$id", types.Uint64Value(1)),
				),
			)
			if err != nil {
				return err
			}
			defer res.Close()
			
			for res.NextResultSet(ctx) {
				for res.NextRow() {
					var (
						id        uint64
						name      string
						createdAt time.Time
					)
					if err := res.Scan(&id, &name, &createdAt); err != nil {
						return err
					}
					fmt.Printf("id: %d, name: %q, created_at: %v\n", id, name, createdAt)
				}
			}
			return res.Err()
		},
	)
}

2. 通过 database/sql 接口使用

安装

go get github.com/ydb-platform/ydb-go-sdk/v3
go get github.com/ydb-platform/ydb-go-sdk-auth-environ

基本示例

package main

import (
	"context"
	"database/sql"
	"fmt"
	"log"
	"time"

	"github.com/ydb-platform/ydb-go-sdk/v3"
	ydbsql "github.com/ydb-platform/ydb-go-sdk/v3/sql"
)

func main() {
	ctx := context.Background()
	
	// 创建连接
	dsn := "grpcs://ydb.serverless.yandexcloud.net:2135/ru-central1/b1g8skpblkos03malf3s/etn02qso4h3isjb00te1"
	nativeDriver, err := ydb.Open(ctx, dsn)
	if err != nil {
		log.Fatal(err)
	}
	defer nativeDriver.Close(ctx)

	// 创建 database/sql 连接
	connector, err := ydbsql.Connector(nativeDriver)
	if err != nil {
		log.Fatal(err)
	}
	
	db := sql.OpenDB(connector)
	defer db.Close()

	// 创建表
	_, err = db.ExecContext(ctx, `
		CREATE TABLE IF NOT EXISTS example_sql (
			id Uint64,
			name Utf8,
			created_at Timestamp,
			PRIMARY KEY (id)
		)
	`)
	if err != nil {
		log.Fatal(err)
	}

	// 插入数据
	_, err = db.ExecContext(ctx, `
		UPSERT INTO example_sql (id, name, created_at) VALUES (?, ?, ?)
	`, 1, "Bob", time.Now())
	if err != nil {
		log.Fatal(err)
	}

	// 查询数据
	rows, err := db.QueryContext(ctx, `
		SELECT id, name, created_at FROM example_sql WHERE id = ?
	`, 1)
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		var (
			id        uint64
			name      string
			createdAt time.Time
		)
		if err := rows.Scan(&id, &name, &createdAt); err != nil {
			log.Fatal(err)
		}
		fmt.Printf("id: %d, name: %q, created_at: %v\n", id, name, createdAt)
	}
	if err := rows.Err(); err != nil {
		log.Fatal(err)
	}
}

两种方式的比较

  1. 原生驱动 (ydb-go-sdk)

    • 提供更完整的 YDB 功能支持
    • 支持更精细的控制和优化
    • 性能更好
    • 语法更接近 YDB 原生接口
  2. database/sql 接口

    • 更符合标准 SQL 接口习惯
    • 可以更容易地与其他数据库切换
    • 代码更简洁
    • 功能可能受限于标准接口的限制

最佳实践建议

  • 如果项目需要充分利用 YDB 的特定功能,建议使用原生驱动
  • 如果项目需要数据库抽象层或可能切换数据库,建议使用 database/sql 接口
  • 对于新项目,可以从 database/sql 接口开始,需要时再切换到原生驱动

两种方式可以混合使用,因为 ydb-go-sdk 提供了 Connector 接口,可以在同一个应用中同时使用两种方式访问 YDB。

回到顶部