Приложение на Go (архивная версия v1)
На этой странице подробно разбирается код тестового приложения, доступного в составе v1 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"
"github.com/yandex-cloud/ydb-go-sdk/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 = `
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(),
)
if err != nil {
return err
}
return res.Err()
}),
)
if err != nil {
// обработка ошибки выполнения запроса
}
Обработка результатов выполнения
Результат выполнения запроса:
log.Println("> select_simple_transaction:")
for res.NextSet() {
for res.NextRow() {
res.SeekItem("series_id")
id := res.OUint64()
res.NextItem()
title := res.OUTF8()
res.NextItem()
date := res.OString()
log.Printf(
"# SeriesID: %d , Title: %s, Date: %s\n",
id, title, date,
)
}
}
Скан запросы
Выполняется скан запрос данных, результатом исполнения которого является стрим. Стрим позволяет считать неограниченное количество строк и объем данных.
var (
query = `
DECLARE $series AS List<UInt64>;
SELECT series_id, season_id, title, CAST(CAST(first_aired AS Date) AS String) AS first_aired
FROM seasons
WHERE series_id IN $series
`
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(
table.ValueParam("$series",
ydb.ListValue(
ydb.Uint64Value(1),
ydb.Uint64Value(10),
),
),
),
)
if err != nil {
return err
}
return res.Err()
}),
)
if err != nil {
// обработка ошибки выполнения запроса
}
Результат выполнения запроса:
log.Println("> scan_query_select:")
for res.NextStreamSet(ctx) {
if err = res.Err(); err != nil {
return err
}
for res.NextRow() {
res.SeekItem("series_id")
id := res.OUint64()
res.SeekItem("season_id")
season := res.OUint64()
res.SeekItem("title")
title := res.OUTF8()
res.SeekItem("first_aired")
date := res.OString()
log.Printf("# Season, SeriesId: %d, SeasonId: %d, Title: %s, Air date: %s\n", id, season, title, date)
}
}
if err = res.Err(); err != nil {
return err
}
return nil
Обработка ошибок
Подробно об обработке ошибок написано в разделе Обработка ошибок в API.