Приложение на Go
На этой странице подробно разбирается код тестового приложения, использующего Go SDK YDB.
Скачивание и запуск
Приведенный ниже сценарий запуска использует git и Go. Предварительно должен быть установлен YDB Go SDK.
Создайте рабочую директорию и выполните в ней из командной строки команду клонирования репозитория с GitHub:
git clone https://github.com/ydb-platform/ydb-go-examples/
Далее из этой же рабочей директории выполните команду запуска тестового приложения, которая будет отличаться в зависимости от того, к какой базе данных необходимо подключиться.
Для соединения с развернутой локальной базой данных YDB по сценарию Docker в конфигурации по умолчанию выполните следующую команду:
( export YDB_ANONYMOUS_CREDENTIALS=1 && cd ydb-go-examples && \
go run ./basic -ydb="grpc://localhost:2136?database=/local" )
Для выполнения примера с использованием любой доступной базы данных YDB вам потребуется знать эндпоинт и путь базы данных.
Если в базе данных включена аутентификация, то вам также понадобится выбрать режим аутентификации и получить секреты - токен или логин/пароль.
Выполните команду по следующему образцу:
( export <auth_mode_var>="<auth_mode_value>" && cd ydb-go-examples && \
go run ./basic -ydb="<endpoint>?database=<database>" )
, где
<endpoint>
- эндпоинт.<database>
- путь базы данных.<auth_mode_var
> - переменная окружения, определяющая режим аутентификации.<auth_mode_value>
- значение параметра аутентификации для выбранного режима.
Например:
( export YDB_ACCESS_TOKEN_CREDENTIALS="t1.9euelZqOnJuJlc..." && cd ydb-go-examples && \
go run ./basic -ydb="grpcs://ydb.example.com:2135?database=/somepath/somelocation" )
Инициализация соединения с базой данных
Для взаимодействия с YDB создается экземпляр драйвера, клиента и сессии:
- Драйвер YDB отвечает за взаимодействие приложения и YDB на транспортном уровне. Драйвер должен существовать на всем протяжении жизненного цикла работы с YDB и должен быть инициализирован перед созданием клиента и сессии.
- Клиент YDB работает поверх драйвера YDB и отвечает за работу с сущностями и транзакциями.
- Сессия YDB содержит информацию о выполняемых транзакциях и подготовленных запросах и содержится в контексте клиента YDB.
Для работы с YDB в go
следует импортировать пакет драйвера ydb-go-sdk
:
import (
// общие импорты из стандартной библиотеки
"context"
"log"
"path"
// импорты пакетов ydb-go-sdk
"github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/table" // для работы с table-сервисом
"github.com/ydb-platform/ydb-go-sdk/v3/table/options" // для работы с table-сервисом
"github.com/ydb-platform/ydb-go-sdk/v3/table/result" // для работы с table-сервисом
"github.com/ydb-platform/ydb-go-sdk/v3/table/result/named" // для работы с table-сервисом
"github.com/ydb-platform/ydb-go-sdk/v3/table/types" // для работы с типами YDB и значениями
"github.com/ydb-platform/ydb-go-sdk-auth-environ" // для аутентификации с использованием перменных окружения
"github.com/ydb-platform/ydb-go-yc" // для работы с YDB в Яндекс Облаке
)
Фрагмент кода приложения для инициализации драйвера:
ctx := context.Background()
// строка подключения
dsn := "grpcs://ydb.serverless.yandexcloud.net:2135/?database=/ru-central1/b1g8skpblkos03malf3s/etn01f8gv9an9sedo9fu"
// IAM-токен
token := "t1.9euelZrOy8aVmZKJm5HGjceMkMeVj-..."
// создаем объект подключения db, является входной точкой для сервисов YDB
db, err := ydb.Open(ctx, dsn,
// yc.WithInternalCA(), // используем сертификаты Яндекс Облака
ydb.WithAccessTokenCredentials(token), // аутентификация с помощью токена
// ydb.WithAnonimousCredentials(), // анонимная аутентификация (например, в docker ydb)
// yc.WithMetadataCredentials(token), // аутентификация изнутри виртуальной машины в Яндекс Облаке или из Яндекс Функции
// yc.WithServiceAccountKeyFileCredentials("~/.ydb/sa.json"), // аутентификация в Яндекс Облаке с помощью файла сервисного аккаунта
// environ.WithEnvironCredentials(ctx), // аутентификация с использованием переменных окружения
)
if err != nil {
// обработка ошибки подключения
}
// закрытие драйвера по окончании работы программы обязательно
defer db.Close(ctx)
Объект db
является входной точкой для работы с сервисами YDB
.
Для работы сервисом таблиц следует использовать клиента table-сервиса db.Table()
.
Клиент table-сервиса предоставляет API
для выполнения запросов над таблицами.
Наиболее востребован метод db.Table().Do(ctx, op)
, который реализует фоновое создание сессий и повторные попытки выполнить пользовательскую операцию op
, в которую пользовательскому коду отдается подготовленная сессия.
Сессия имеет исчерпывающее API
, позволяющее выполнять DDL
, DML
, DQL
и TCL
запросы.
Создание строковых таблиц
Выполняется создание строковых таблиц, которые используются в дальнейших операциях тестового приложения. В результате исполнения шага в базе данных будут созданы строковые таблицы модели данных справочника сериалов:
series
- Сериалыseasons
- Сезоныepisodes
- Эпизоды
После создания вызывается метод получения информации об объекте схемы данных, и выводится результат его выполнения.
Для создания строковых таблиц используется метод table.Session.CreateTable()
:
err = db.Table().Do(ctx,
func(ctx context.Context, s table.Session) (err error) {
return s.CreateTable(ctx, path.Join(db.Name(), "series"),
options.WithColumn("series_id", types.TypeUint64), // not null column
options.WithColumn("title", types.Optional(types.TypeUTF8)),
options.WithColumn("series_info", types.Optional(types.TypeUTF8)),
options.WithColumn("release_date", types.Optional(types.TypeDate)),
options.WithColumn("comment", types.Optional(types.TypeUTF8)),
options.WithPrimaryKeyColumn("series_id"),
)
},
)
if err != nil {
// обработка ситуации, когда не удалось выполнить запрос
}
Метод table.Session.CreateTable()
не позволяет создавать колоночные таблицы. Это можно сделать с помощью метода table.Session.Execute()
, который выполняет YQL-запросы.
Если вы создали строковую таблицу и хотите вывести информацию о её структуре и убедиться, что она успешно создалась, воспользуйтесь методом table.Session.DescribeTable()
:
err = db.Table().Do(ctx,
func(ctx context.Context, s table.Session) (err error) {
desc, err := s.DescribeTable(ctx, path.Join(db.Name(), "series"))
if err != nil {
return
}
log.Printf("> describe table: %s\n", tableName)
for _, c := range desc.Columns {
log.Printf(" > column, name: %s, %s\n", c.Type, c.Name)
}
return
},
)
if err != nil {
// обработка ситуации, когда не удалось выполнить запрос
}
Получение выборки данных
Выполняется запрос на получение выборки данных с использованием команды SELECT
языка запросов YQL. Демонстрируется обработка полученной выборки в приложении.
Для выполнения YQL-запросов используется метод table.Session.Execute()
.
SDK позволяет в явном виде контролировать выполнение транзакций и настраивать необходимый режим выполнения транзакций с помощью структуры table.TxControl
.
var (
readTx = table.TxControl(
table.BeginTx(
table.WithOnlineReadOnly(),
),
table.CommitTx(),
)
)
err := db.Table().Do(ctx,
func(ctx context.Context, s table.Session) (err error) {
var (
res result.Result
id uint64 // переменная для required результатов
title *string // указатель - для опциональных результатов
date *time.Time // указатель - для опциональных результатов
)
_, res, err = s.Execute(
ctx,
readTx,
`
DECLARE $seriesID AS Uint64;
SELECT
series_id,
title,
release_date
FROM
series
WHERE
series_id = $seriesID;
`,
table.NewQueryParameters(
table.ValueParam("$seriesID", types.Uint64Value(1)), // подстановка в условие запроса
),
)
if err != nil {
return err
}
defer res.Close() // закрытие result'а обязательно
log.Printf("> select_simple_transaction:\n")
for res.NextResultSet(ctx) {
for res.NextRow() {
// в ScanNamed передаем имена колонок из строки сканирования,
// адреса (и типы данных), куда следует присвоить результаты запроса
err = res.ScanNamed(
named.Optional("series_id", &id),
named.Optional("title", &title),
named.Optional("release_date", &date),
)
if err != nil {
return err
}
log.Printf(
" > %d %s %s\n",
id, *title, *date,
)
}
}
return res.Err()
},
)
if err != nil {
// обработка ошибки выполнения запроса
}
Скан запросы
Выполняется скан запрос данных, результатом исполнения которого является стрим. Стрим позволяет считать неограниченное количество строк и объем данных.
Для выполнения scan-запросов используется метод table.Session.StreamExecuteScanQuery()
.
var (
query = `
DECLARE $series AS List<UInt64>;
SELECT series_id, season_id, title, first_aired
FROM seasons
WHERE series_id IN $series
`
res result.StreamResult
)
err = c.Do(ctx,
func(ctx context.Context, s table.Session) (err error) {
res, err = s.StreamExecuteScanQuery(ctx, query,
table.NewQueryParameters(
table.ValueParam("$series",
types.ListValue(
types.Uint64Value(1),
types.Uint64Value(10),
),
),
),
)
if err != nil {
return err
}
defer res.Close() // закрытие result'а обязательно
var (
seriesID uint64
seasonID uint64
title string
date time.Time
)
log.Print("\n> scan_query_select:")
for res.NextResultSet(ctx) {
if err = res.Err(); err != nil {
return err
}
for res.NextRow() {
// named.OptionalWithDefault позволяет "развернуть" опциональные
// результаты или использовать дефолтное значение типа go
err = res.ScanNamed(
named.Required("series_id", &seriesID),
named.OptionalWithDefault("season_id", &seasonID),
named.OptionalWithDefault("title", &title),
named.OptionalWithDefault("first_aired", &date),
)
if err != nil {
return err
}
log.Printf("# Season, SeriesId: %d, SeasonId: %d, Title: %s, Air date: %s", seriesID, seasonID, title, date)
}
}
return res.Err()
},
)
if err != nil {
// обработка ошибки выполнения запроса
}