Приложение на Go
На этой странице подробно разбирается код тестового приложения, использующего YDB Go SDK.
Скачивание и запуск
Приведенный ниже сценарий запуска использует git и Go. Предварительно должен быть установлен YDB Go SDK.
Создайте рабочую директорию и выполните в ней из командной строки команду клонирования репозитория с GitHub:
git clone https://github.com/ydb-platform/ydb-go-sdk.git
Далее из этой же рабочей директории выполните команду запуска тестового приложения, которая будет отличаться в зависимости от того, к какой базе данных необходимо подключиться.
Для соединения с развернутой локальной базой данных YDB по сценарию Docker в конфигурации по умолчанию выполните следующую команду:
( export YDB_ANONYMOUS_CREDENTIALS=1 && cd ydb-go-sdk/examples && \
go run ./basic/native/query -ydb="grpc://localhost:2136/local" )
Для выполнения примера с использованием любой доступной базы данных YDB вам потребуется знать эндпоинт и путь базы данных.
Если в базе данных включена аутентификация, то вам также понадобится выбрать режим аутентификации и получить секреты - токен или логин/пароль.
Выполните команду по следующему образцу:
( export <auth_mode_var>="<auth_mode_value>" && cd ydb-go-sdk/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-sdk/examples && \
go run ./basic -ydb="grpcs://ydb.example.com:2135/somepath/somelocation" )
Инициализация соединения с базой данных
Для взаимодействия с YDB создается экземпляр драйвера, клиента и сессии:
- Драйвер YDB отвечает за взаимодействие приложения и YDB на транспортном уровне. Драйвер должен существовать на всем протяжении жизненного цикла работы с YDB и должен быть инициализирован перед созданием клиента и сессии.
- Клиент YDB работает поверх драйвера YDB и отвечает за работу с сущностями и транзакциями.
- Сессия YDB содержит информацию о выполняемых транзакциях и подготовленных запросах и содержится в контексте клиента YDB.
Для работы с YDB в go следует импортировать пакет драйвера ydb-go-sdk:
import (
"context"
"log"
"path"
"github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/query"
)
Для взаимодействия с YDB необходимо создать экземляр YDB-драйвера:
db, err := ydb.Open(context.Background(), "grpc://localhost:2136/local")
if err != nil {
// обработка ошибки подключения
}
// При заверщении работы с базой (например, выходе из программы) закройте драйвер
defer db.Close(context.Background())
Метод ydb.Open возвращает в случае успеха экземпляр драйвера, который выполняет ряд служебных функций, таких как актуализация сведений о кластере YDB и клиентская балансировка.
Метод ydb.Open принимает два обязательных аргумента:
- контекст;
- строка подключения к YDB.
Также доступно множество опций подключения, позволяющих переопределить значения по умолчанию.
По умолчанию используется анонимная аутентификация. А подключение к кластеру YDB с использованием токена будет иметь следующий вид:
db, err := ydb.Open(context.Background(), clusterEndpoint,
ydb.WithAccessTokenCredentials(token),
)
Полный список провайдеров аутентификации приведён в документации ydb-go-sdk и в разделе рецептов.
В конце работы приложения для очистки ресурсов следует закрыть драйвер:
defer db.Close(ctx)
Объект db является входной точкой для работы с YDB, а для запросов к таблицам используется Query-сервис db.Query().
Выполнение YQL-запросов осуществляется на специальных объектах — сессиях query.Session. Сессии хранят контекст выполнения запросов (например, транзакции) и позволяют осуществлять серверную балансировку нагрузки на узлы кластера YDB.
Клиент Query-сервиса предоставляет API для выполнения запросов к таблицам:
- Метод
db.Query().Do(ctx, op)реализует фоновое создание сессий и повторные попытки выполнить пользовательскую операциюop func(ctx context.Context, s query.Session) error, в которую пользовательскому коду передаётся подготовленная сессияquery.Session. - Метод
db.Query().DoTx(ctx, op)принимает пользовательскую операциюop func(ctx context.Context, tx query.TxActor) error, в которую пользовательскому коду передаётся подготовленная (заранее открытая) транзакцияquery.TxActor. Автоматическое выполнениеCommitтранзакции происходит, если из пользовательской операции возвращаетсяnil. В случае возврата ошибки для текущей транзакции автоматически вызываетсяRollback. - Метод
db.Query().Execявляется вспомогательным и предназначен для выполнения единичного запроса без результата с автоматическими повторными попытками. МетодExecвозвращаетnilв случае успешного выполнения запроса и ошибку, если операция не удалась. - Метод
db.Query().Queryявляется вспомогательным и предназначен для выполнения единичного запроса с повторными попытками при необходимости. Текст запроса может содержать несколько выражений с результатами. МетодQueryвозвращает, в случае успеха, материализованный результат запроса (все данные уже прочитаны с сервера и доступны в локальной памяти)query.Resultи позволяет итерироваться по вложенным спискам строкquery.ResultSet. Для широких SQL-запросов, возвращающих большое количество строк, материализация результата может привести к проблеме OOM. - Метод
db.Query().QueryResultSetявляется вспомогательным и предназначен для выполнения единичного запроса с повторными попытками при необходимости. В запросе должно быть ровно одно выражение, возвращающее результат (дополнительно могут присутствовать выражения, не возвращающие результат, напримерUPSERT). МетодQueryResultSetвозвращает, в случае успеха, материализованный список результатовquery.ResultSet. Для широких SQL-запросов, возвращающих большое количество строк, материализация результата может привести к проблеме OOM. - Метод
db.Query().QueryRowявляется вспомогательным и предназначен для выполнения единичного запроса с повторными попытками при необходимости. МетодQueryRowвозвращает, в случае успеха, единственную строкуquery.Row.
Создание строковых таблиц
Выполняется создание строковых таблиц, которые используются в дальнейших операциях тестового приложения. В результате исполнения шага в базе данных будут созданы строковые таблицы модели данных справочника сериалов:
series- Сериалыseasons- Сезоныepisodes- Эпизоды
После создания вызывается метод получения информации об объекте схемы данных, и выводится результат его выполнения.
Пример запроса без возвращаемого результата (создание таблицы):
import "github.com/ydb-platform/ydb-go-sdk/v3/query"
err = db.Query().Exec(ctx, `
CREATE TABLE IF NOT EXISTS series (
series_id Bytes,
title Text,
series_info Text,
release_date Date,
comment Text,
PRIMARY KEY(series_id)
)`, query.WithTxControl(query.NoTx()),
)
if err != nil {
// обработка ошибки выполнения запроса
}
Получение выборки данных
Выполняется запрос на получение выборки данных с использованием команды SELECT языка запросов YQL. Демонстрируется обработка полученной выборки в приложении.
Для выполнения YQL-запросов и чтения результатов используются методы query.Session.Query, query.Session.QueryResultSet и query.Session.QueryRow.
SDK позволяет явно контролировать выполнение транзакций и настраивать необходимый режим выполнения транзакций с помощью структуры query.TxControl.
readTx := query.TxControl(
query.BeginTx(
query.WithSnapshotReadOnly(),
),
query.CommitTx(),
)
row, err := db.Query().QueryRow(ctx,`
DECLARE $seriesID AS Uint64;
SELECT
series_id,
title,
release_date
FROM
series
WHERE
series_id = $seriesID;`,
query.WithParameters(
ydb.ParamsBuilder().Param("$seriesID").Uint64(1).Build(),
),
query.WithTxControl(readTx),
)
if err != nil {
// обработка ошибки выполнения запроса
}
Для получения данных строки query.Row можно использовать следующие методы:
query.Row.ScanStruct— по названиям колонок, зафиксированным в тегах структуры.query.Row.ScanNamed— по названиям колонок.query.Row.Scan— по порядку колонок.
var info struct {
SeriesID string `sql:"series_id"`
Title string `sql:"title"`
ReleaseDate time.Time `sql:"release_date"`
}
err = row.ScanStruct(&info)
if err != nil {
// обработка ошибки выполнения запроса
}
var seriesID, title string
var releaseDate time.Time
err = row.ScanNamed(query.Named("series_id", &seriesID), query.Named("title", &title), query.Named("release_date", &releaseDate))
if err != nil {
// обработка ошибки выполнения запроса
}
var seriesID, title string
var releaseDate time.Time
err = row.Scan(&seriesID, &title, &releaseDate)
if err != nil {
// обработка ошибки выполнения запроса
}
Важно
Если ожидаемый объём данных от запроса велик, не следует пытаться загружать их полностью в оперативную память с помощью вспомогательных методов, таких как query.Client.Query и query.Client.QueryResultSet. Эти методы возвращают уже материализованный результат, при котором все данные запроса загружены с сервера в локальную память клиентского приложения. При большом количестве возвращаемых строк материализация результата может привести к проблеме OOM.
Для таких запросов следует использовать методы query.TxActor.Query или query.TxActor.QueryResultSet на сессии или транзакции, которые предоставляют итератор по результату без полной материализации. Сессия query.Session доступна только из метода query.Client.Do, реализующего механизмы повторных попыток при ошибках. Нужно учитывать, что чтение может быть прервано в любой момент, и в таком случае весь процесс выполнения запроса начнётся заново. То есть функция, переданная в Do, может вызываться более одного раза.
err = db.Query().Do(ctx,
func(ctx context.Context, s query.Session) error {
rows, err := s.QueryResultSet(ctx,`
SELECT series_id, season_id, title, first_aired
FROM seasons`,
)
if err != nil {
return err
}
defer rows.Close(ctx)
for row, err := range rows.Rows(ctx) {
if err != nil {
return err
}
var info struct {
SeriesID string `sql:"series_id"`
SeasonID string `sql:"season_id"`
Title string `sql:"title"`
FirstAired time.Time `sql:"first_aired"`
}
err = row.ScanStruct(&info)
if err != nil {
return err
}
fmt.Printf("%+v\n", info)
}
return nil
},
query.WithIdempotent(),
)
if err != nil {
// обработка ошибки выполнения запроса
}