Приложение на Go (архивная версия v2)
На этой странице подробно разбирается код тестового приложения, доступного в составе v2 Go SDK YDB.
Инициализация соединения с базой данных
Для взаимодействия с YDB создается экземпляр драйвера, клиента и сессии:
- Драйвер YDB отвечает за взаимодействие приложения и YDB на транспортном уровне. Драйвер должен существовать на всем протяжении жизненного цикла работы с YDB и должен быть инициализирован перед созданием клиента и сессии.
- Клиент YDB работает поверх драйвера YDB и отвечает за работу с сущностями и транзакциями.
- Сессия YDB содержит информацию о выполняемых транзакциях и подготовленных запросах и содержится в контексте клиента YDB.
Для работы с YDB в go
следует импортировать пакет драйвера ydb-go-sdk
:
import (
// общие импорты
"context"
"path"
// импорты пакетов ydb-go-sdk
"github.com/yandex-cloud/ydb-go-sdk/v2"
"github.com/yandex-cloud/ydb-go-sdk/v2/table" // для работы с table-сервисом
)
Фрагмент кода приложения для инициализации драйвера:
func (cmd *Command) Run(ctx context.Context, params cli.Parameters) error {
dialer := &ydb.Dialer{
DriverConfig: cmd.config(params),
TLSConfig: cmd.tls(),
Timeout: time.Second,
}
driver, err := dialer.Dial(ctx, params.Endpoint)
if err != nil {
return fmt.Errorf("dial error: %v", err)
}
defer driver.Close()
Фрагмент кода приложения для создания сессии:
tableClient := table.Client{
Driver: driver,
}
sp := table.SessionPool{
IdleThreshold: time.Second,
Builder: &tableClient,
}
defer sp.Close(ctx)
Создание таблиц
Выполняется создание таблиц, которые используются в дальнейших операциях тестового приложения. В результате исполнения шага в базе данных будут созданы таблицы модели данных справочника сериалов:
series
- Сериалыseasons
- Сезоныepisodes
- Эпизоды
После создания вызывается метод получения информации об объекте схемы данных, и выводится результат его выполнения.
Для создания таблиц используется метод Session.CreateTable()
:
func createTables(ctx context.Context, sp *table.SessionPool, prefix string) (err error) {
err = table.Retry(ctx, sp,
table.OperationFunc(func(ctx context.Context, s *table.Session) error {
return s.CreateTable(ctx, path.Join(prefix, "series"),
table.WithColumn("series_id", ydb.Optional(ydb.TypeUint64)),
table.WithColumn("title", ydb.Optional(ydb.TypeUTF8)),
table.WithColumn("series_info", ydb.Optional(ydb.TypeUTF8)),
table.WithColumn("release_date", ydb.Optional(ydb.TypeUint64)),
table.WithColumn("comment", ydb.Optional(ydb.TypeUTF8)),
table.WithPrimaryKeyColumn("series_id"),
)
}),
)
С помощью метода Session.DescribeTable()
можно вывести информацию о структуре таблицы и убедиться, что она успешно создалась:
func describeTable(ctx context.Context, sp *table.SessionPool, path string) (err error) {
err = table.Retry(ctx, sp,
table.OperationFunc(func(ctx context.Context, s *table.Session) error {
desc, err := s.DescribeTable(ctx, path)
if err != nil {
return err
}
log.Printf("\n> describe table: %s", path)
for _, c := range desc.Columns {
log.Printf("column, name: %s, %s", c.Type, c.Name)
}
return nil
}),
)
Получение выборки данных
Выполняется запрос на получение выборки данных с использованием команды SELECT
языка запросов YQL. Демонстрируется обработка полученной выборки в приложении.
Для выполнения YQL-запросов используется метод Session.Execute()
.
SDK позволяет в явном виде контролировать выполнение транзакций и настраивать необходимый режим выполнения транзакций с помощью класса TxControl
.
var (
query = `--!syntax_v1
DECLARE $seriesID AS Uint64;
$format = DateTime::Format("%Y-%m-%d");
SELECT
series_id,
title,
$format(DateTime::FromSeconds(CAST(DateTime::ToSeconds(DateTime::IntervalFromDays(CAST(release_date AS Int16))) AS Uint32))) AS release_date
FROM
series
WHERE
series_id = $seriesID;`
res *table.Result
)
readTx := table.TxControl(
table.BeginTx(
table.WithOnlineReadOnly(),
),
table.CommitTx(),
)
err = table.Retry(ctx, sp,
table.OperationFunc(func(ctx context.Context, s *table.Session) (err error) {
_, res, err = s.Execute(ctx, readTx, query,
table.NewQueryParameters(
table.ValueParam("$seriesID", ydb.Uint64Value(1)),
),
table.WithQueryCachePolicy(
table.WithQueryCachePolicyKeepInCache(),
),
table.WithCollectStatsModeBasic(),
)
return
}),
)
if err != nil {
return err
}
Обработка результатов выполнения
Результат выполнения запроса:
var (
id *uint64
title *string
date *[]byte
)
log.Println("> select_simple_transaction:")
for res.NextResultSet(ctx, "series_id", "title", "release_date") {
for res.NextRow() {
err = res.Scan(&id, &title, &date)
if err != nil {
return err
}
log.Printf(
"# SeriesID: %d , Title: %s, Date: %s\n",
*id, *title, *date,
)
}
}
if err = res.Err(); err != nil {
return err
}
return nil
}
Скан запросы
Выполняется скан запрос данных, результатом исполнения которого является стрим. Стрим позволяет считать неограниченное количество строк и объем данных.
var (
query = `
SELECT series_id, season_id, COUNT(*) AS episodes_count
FROM episodes
GROUP BY series_id, season_id
ORDER BY series_id, season_id;`
res *table.Result
)
err = table.Retry(ctx, sp,
table.OperationFunc(func(ctx context.Context, s *table.Session) (err error) {
res, err = s.StreamExecuteScanQuery(ctx, query, table.NewQueryParameters())
return err
}),
)
if err != nil {
return err
}
Результат выполнения запроса:
var (
seriesID uint64
seasonID uint64
count uint64
)
log.Println("> scan_query_select:")
for res.NextResultSet(ctx, "series_id", "season_id", "episodes_count") {
for res.NextRow() {
err = res.ScanWithDefaults(&seriesID, &seasonID, &count)
if err != nil {
return err
}
log.Printf("# Season, SeriesId: %d, SeasonId: %d, Count: %d\n", seriesID, seasonID, count)
}
}
if err = res.Err(); err != nil {
return err
}
return nil
}
Обработка ошибок
Подробно об обработке ошибок написано в разделе Обработка ошибок в API.