aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoralexandr268 <alexandr268@yandex-team.ru>2022-04-06 21:52:40 +0300
committeralexandr268 <alexandr268@yandex-team.ru>2022-04-06 21:52:40 +0300
commitbcc94a11eb3b4cd7f8c80f5eb4b5e5eb832f74fc (patch)
treede4672a6642c1fd81baea293634006527e2d0908
parent3b53fc30368aa56b2cdcfeaf8215cbc680fce307 (diff)
downloadydb-bcc94a11eb3b4cd7f8c80f5eb4b5e5eb832f74fc.tar.gz
Update Java SDK example and documentation KIKIMR-14232
Add run options for Java SDK example Update Java SDK example documentation Update simple project Fix broken link to cpp example Update simple project example Update basic example ref:287f21d20bb80e5667f2c8f295c06dab0ed351ae
-rw-r--r--ydb/docs/ru/core/getting_started/_includes/sdk.md1
-rw-r--r--ydb/docs/ru/core/reference/ydb-sdk/example/_includes/index.md18
-rw-r--r--ydb/docs/ru/core/reference/ydb-sdk/example/example-java.md2
-rw-r--r--ydb/docs/ru/core/reference/ydb-sdk/example/java/_includes/run_custom.md23
-rw-r--r--ydb/docs/ru/core/reference/ydb-sdk/example/java/_includes/run_docker.md5
-rw-r--r--ydb/docs/ru/core/reference/ydb-sdk/example/java/_includes/run_options.md11
-rw-r--r--ydb/docs/ru/core/reference/ydb-sdk/example/java/index.md369
-rw-r--r--ydb/docs/ru/core/reference/ydb-sdk/example/toc_i.yaml2
-rw-r--r--ydb/docs/ru/core/reference/ydb-sdk/recipes/session_pool_limit/_includes/java.md7
-rw-r--r--ydb/docs/ru/core/reference/ydb-sdk/recipes/session_pool_limit/index.md4
10 files changed, 430 insertions, 12 deletions
diff --git a/ydb/docs/ru/core/getting_started/_includes/sdk.md b/ydb/docs/ru/core/getting_started/_includes/sdk.md
index 5aabebc2b2..93fe95d9cb 100644
--- a/ydb/docs/ru/core/getting_started/_includes/sdk.md
+++ b/ydb/docs/ru/core/getting_started/_includes/sdk.md
@@ -10,5 +10,6 @@
* [Python](../../reference/ydb-sdk/example/python/index.md)
* [Go](../../reference/ydb-sdk/example/go/index.md)
+ * [Java](../../reference/ydb-sdk/example/java/index.md)
Полная информация о {{ ydb-short-name }} SDK находится в разделе [Работа с {{ ydb-short-name }} SDK](../../reference/ydb-sdk/index.md).
diff --git a/ydb/docs/ru/core/reference/ydb-sdk/example/_includes/index.md b/ydb/docs/ru/core/reference/ydb-sdk/example/_includes/index.md
index fa5a4b70ab..46bade084c 100644
--- a/ydb/docs/ru/core/reference/ydb-sdk/example/_includes/index.md
+++ b/ydb/docs/ru/core/reference/ydb-sdk/example/_includes/index.md
@@ -7,7 +7,7 @@
{% endif %}
- [С# (.NET)](../example-dotnet.md)
- [Go](../go/index.md)
-- [Java](../example-java.md)
+- [Java](../java/index.md)
- [Node.js](../example-nodejs.md)
- [Python](../python/index.md)
@@ -15,35 +15,35 @@
{% include [init.md](steps/01_init.md) %}
-{% if oss %}[C++](../example-cpp.md#init) | {% endif %} [C# (.NET)](../example-dotnet.md#init) | [Go](../go/index.md#init) | [Java](../example-java.md#init) | Node.js | [PHP](../example-php.md#init) | [Python](../python/index.md#init)
+{% if oss %}[C++](../example-cpp.md#init) | {% endif %} [C# (.NET)](../example-dotnet.md#init) | [Go](../go/index.md#init) | [Java](../java/index.md#init) | Node.js | [PHP](../example-php.md#init) | [Python](../python/index.md#init)
{% include [create_table.md](steps/02_create_table.md) %}
-{% if oss %}[C++](../example-cpp.md#create-table) | {% endif %} [C# (.NET)](../example-dotnet.md#create-table) | [Go](../go/index.md#create-table) | [Java](../example-java.md#create-table) | Node.js | PHP | [Python](../python/index.md#create-table)
+{% if oss %}[C++](../example-cpp.md#create-table) | {% endif %} [C# (.NET)](../example-dotnet.md#create-table) | [Go](../go/index.md#create-table) | [Java](../java/index.md#create-table) | Node.js | PHP | [Python](../python/index.md#create-table)
{% include [write_queries.md](steps/03_write_queries.md) %}
-{% if oss %}[C++](../example-cpp.md#write-queries) | {% endif %} [C# (.NET)](../example-dotnet.md#write-queries) | Go | [Java](../example-java.md#write-queries) | Node.js | PHP | [Python](../python/index.md#write-queries)
+{% if oss %}[C++](../example-cpp.md#write-queries) | {% endif %} [C# (.NET)](../example-dotnet.md#write-queries) | Go | [Java](../java/index.md#write-queries) | Node.js | PHP | [Python](../python/index.md#write-queries)
{% include [query_processing.md](steps/04_query_processing.md) %}
-{% if oss %}[C++](../example-cpp.md#query-processing) | {% endif %} [C# (.NET)](../example-dotnet.md#query-processing) | [Go](../go/index.md#query-processing) | [Java](../example-java.md#query-processing) | Node.js | PHP | [Python](../python/index.md#query-processing)
+{% if oss %}[C++](../example-cpp.md#query-processing) | {% endif %} [C# (.NET)](../example-dotnet.md#query-processing) | [Go](../go/index.md#query-processing) | [Java](../java/index.md#query-processing) | Node.js | PHP | [Python](../python/index.md#query-processing)
{% include [param_queries.md](steps/06_param_queries.md) %}
-{% if oss %}[C++](../example-cpp.md#param-queries) | {% endif %} [C# (.NET)](../example-dotnet.md#param-queries) | [Go](../go/index.md#param-queries) | [Java](../example-java.md#param-queries) | Node.js | PHP | [Python](../python/index.md#param-queries)
+{% if oss %}[C++](../example-cpp.md#param-queries) | {% endif %} [C# (.NET)](../example-dotnet.md#param-queries) | [Go](../go/index.md#param-queries) | [Java](../java/index.md#param-queries) | Node.js | PHP | [Python](../python/index.md#param-queries)
{% include [scan_query.md](steps/08_scan_query.md) %}
-{% if oss %}C++ | {% endif %} [C# (.NET)](../example-dotnet.md#scan-query) | [Go](../go/index.md#scan-query) | [Java](../example-java.md#scan-query) | [Node.js](../example-nodejs.md#scan-query) | PHP | [Python](../python/index.md#scan-query)
+{% if oss %}C++ | {% endif %} [C# (.NET)](../example-dotnet.md#scan-query) | [Go](../go/index.md#scan-query) | [Java](../java/index.md#scan-query) | [Node.js](../example-nodejs.md#scan-query) | PHP | [Python](../python/index.md#scan-query)
{% include [multistep_transactions.md](steps/09_multistep_transactions.md) %}
-{% if oss %}[C++](../example-cpp.md#multistep-transactions) | {% endif %} C# (.NET) | Go | [Java](../example-java.md#multistep-transactions) | Node.js | PHP | Python
+{% if oss %}[C++](../example-cpp.md#multistep-transactions) | {% endif %} C# (.NET) | Go | [Java](../java/index.md#multistep-transactions) | Node.js | PHP | Python
{% include [transaction_control.md](steps/10_transaction_control.md) %}
-{% if oss %}[C++](../example-cpp.md#tcl) | {% endif %} C# (.NET) | Go | [Java](../example-java.md#tcl) | Node.js | PHP | [Python](../python/index.md#tcl)
+{% if oss %}[C++](../example-cpp.md#tcl) | {% endif %} C# (.NET) | Go | [Java](../java/index.md#tcl) | Node.js | PHP | [Python](../python/index.md#tcl)
{% include [error_handling.md](steps/50_error_handling.md) %}
diff --git a/ydb/docs/ru/core/reference/ydb-sdk/example/example-java.md b/ydb/docs/ru/core/reference/ydb-sdk/example/example-java.md
deleted file mode 100644
index 3306908cf9..0000000000
--- a/ydb/docs/ru/core/reference/ydb-sdk/example/example-java.md
+++ /dev/null
@@ -1,2 +0,0 @@
-{% include [example-java.md](_includes/example-java.md) %}
-
diff --git a/ydb/docs/ru/core/reference/ydb-sdk/example/java/_includes/run_custom.md b/ydb/docs/ru/core/reference/ydb-sdk/example/java/_includes/run_custom.md
new file mode 100644
index 0000000000..79c5d1f0c8
--- /dev/null
+++ b/ydb/docs/ru/core/reference/ydb-sdk/example/java/_includes/run_custom.md
@@ -0,0 +1,23 @@
+Для выполнения примера с использованием любой доступной базы данных YDB вам потребуется знать [Эндпоинт](../../../../../concepts/connect.md#endpoint) и [Размещение базы данных](../../../../../concepts/connect.md#database).
+
+Если в базе данных включена аутентификация, то вам также понадобится выбрать [режим аутентификации](../../../../../concepts/connect.md#auth-modes) и получить секреты - токен или логин/пароль.
+
+Выполните команду по следующему образцу:
+
+``` bash
+<auth_mode_var>="<auth_mode_value>" java -jar examples/simple_project/target/ydb-simple-project.jar <endpoint>?database=<database>
+```
+
+, где
+
+- `<endpoint>` - [Эндпоинт](../../../../../concepts/connect.md#endpoint)
+- `<database>` - [Размещение базы данных](../../../../../concepts/connect.md#database)
+- `<auth_mode_var`> - [Переменная окружения](../../../auth.md#env), определяющая режим аутентификации
+- `<auth_mode_value>` - Значение параметра аутентификации для выбранного режима
+
+Например:
+``` bash
+YDB_ACCESS_TOKEN_CREDENTIALS="t1.9euelZqOnJuJlc..." java -jar examples/simple_project/target/ydb-simple-project.jar grpcs://ydb.example.com:2135?database=/somepath/somelocation
+```
+
+{% include [../../_includes/pars_from_profile_hint.md](../../_includes/pars_from_profile_hint.md) %} \ No newline at end of file
diff --git a/ydb/docs/ru/core/reference/ydb-sdk/example/java/_includes/run_docker.md b/ydb/docs/ru/core/reference/ydb-sdk/example/java/_includes/run_docker.md
new file mode 100644
index 0000000000..4abdddb1cb
--- /dev/null
+++ b/ydb/docs/ru/core/reference/ydb-sdk/example/java/_includes/run_docker.md
@@ -0,0 +1,5 @@
+Для соединения с развернутой локальной базой данных YDB по сценарию [Docker](../../../../../getting_started/self_hosted/ydb_docker.md) в конфигурации по умолчанию выполните следующую команду:
+
+``` bash
+YDB_ANONYMOUS_CREDENTIALS=1 java -jar examples/simple_project/target/ydb-simple-project.jar grpc://localhost:2136?database=/local
+```
diff --git a/ydb/docs/ru/core/reference/ydb-sdk/example/java/_includes/run_options.md b/ydb/docs/ru/core/reference/ydb-sdk/example/java/_includes/run_options.md
new file mode 100644
index 0000000000..a637c6126b
--- /dev/null
+++ b/ydb/docs/ru/core/reference/ydb-sdk/example/java/_includes/run_options.md
@@ -0,0 +1,11 @@
+{% list tabs %}
+
+- Local Docker
+
+ {% include [run_docker.md](run_docker.md) %}
+
+- Любая база данных
+
+ {% include [run_custom.md](run_custom.md) %}
+
+{% endlist %}
diff --git a/ydb/docs/ru/core/reference/ydb-sdk/example/java/index.md b/ydb/docs/ru/core/reference/ydb-sdk/example/java/index.md
new file mode 100644
index 0000000000..89135d2f42
--- /dev/null
+++ b/ydb/docs/ru/core/reference/ydb-sdk/example/java/index.md
@@ -0,0 +1,369 @@
+# Приложение на Java
+
+На этой странице подробно разбирается код [тестового приложения](https://github.com/yandex-cloud/ydb-java-sdk/tree/master/examples/simple_project), доступного в составе [Java SDK](https://github.com/yandex-cloud/ydb-java-sdk) {{ ydb-short-name }}.
+
+## Скачивание SDK и запуск примера {#download}
+
+Приведенный ниже сценарий запуска использует [git](https://git-scm.com/downloads) и [Maven](https://maven.apache.org/download.html).
+
+Создайте рабочую директорию и выполните в ней из командной строки команду клонирования репозитория с github.com:
+
+``` bash
+git clone https://github.com/yandex-cloud/ydb-java-sdk
+```
+
+Далее выполните сборку SDK и входящих в него примеров
+
+``` bash
+cd ydb-java-sdk && mvn clean package
+```
+
+Далее из этой же рабочей директории выполните команду запуска тестового приложения, которая будет отличаться в зависимости от того, к какой базе данных необходимо подключиться.
+
+{% include [run_options.md](_includes/run_options.md) %}
+
+
+{% include [init.md](../_includes/steps/01_init.md) %}
+
+Основные параметры инициализации драйвера
+* Cтрока подключения с информацией об [эндпоинте](../../../../concepts/connect.md#endpoint) и [базе данных](../../../../concepts/connect.md#database). Единственный обязательные параметр.
+* Провайдер [аутенфикации](../../auth.md##auth-provider). В случае отсутсвия прямого указания - будет использоваться [анонимное подключение](../../../../concepts/connect.md#auth-modes).
+* Настройки [пула сессий](../../recipes/session_pool_limit/index.md)
+
+Фрагмент кода приложения для инициализации драйвера:
+
+```java
+GrpcTransport transport = GrpcTransport.forConnectionString(connectionString)
+ .withAuthProvider(CloudAuthHelper.getAuthProviderFromEnviron())
+ .build();
+GrpcTableRpc rpc = GrpcTableRpc.ownTransport(transport);
+this.tableClient = TableClient.newClient(rpc).build();
+```
+
+Все операции с YDB рекомендуется выполнять с помощью класса-хелпера `SessionRetryContext`, который обеспечивает корректное повтороное выполнение операция в случае частичной недоступности. Фрагмент кода для инициализации контекста ретраев:
+
+```java
+this.retryCtx = SessionRetryContext.create(tableClient).build();
+```
+
+{% include [create_table.md](../_includes/steps/02_create_table.md) %}
+
+Для создания таблиц используется метод `Session.createTable()`:
+
+```java
+private void createTables() {
+ TableDescription seriesTable = TableDescription.newBuilder()
+ .addNullableColumn("series_id", PrimitiveType.uint64())
+ .addNullableColumn("title", PrimitiveType.utf8())
+ .addNullableColumn("series_info", PrimitiveType.utf8())
+ .addNullableColumn("release_date", PrimitiveType.date())
+ .setPrimaryKey("series_id")
+ .build();
+
+ retryCtx.supplyStatus(session -> session.createTable(database + "/series", seriesTable))
+ .join().expect("create table problem");
+
+ TableDescription seasonsTable = TableDescription.newBuilder()
+ .addNullableColumn("series_id", PrimitiveType.uint64())
+ .addNullableColumn("season_id", PrimitiveType.uint64())
+ .addNullableColumn("title", PrimitiveType.utf8())
+ .addNullableColumn("first_aired", PrimitiveType.date())
+ .addNullableColumn("last_aired", PrimitiveType.date())
+ .setPrimaryKeys("series_id", "season_id")
+ .build();
+
+ retryCtx.supplyStatus(session -> session.createTable(database + "/seasons", seasonsTable))
+ .join().expect("create table problem");
+
+ TableDescription episodesTable = TableDescription.newBuilder()
+ .addNullableColumn("series_id", PrimitiveType.uint64())
+ .addNullableColumn("season_id", PrimitiveType.uint64())
+ .addNullableColumn("episode_id", PrimitiveType.uint64())
+ .addNullableColumn("title", PrimitiveType.utf8())
+ .addNullableColumn("air_date", PrimitiveType.date())
+ .setPrimaryKeys("series_id", "season_id", "episode_id")
+ .build();
+
+ retryCtx.supplyStatus(session -> session.createTable(database + "/episodes", episodesTable))
+ .join().expect("create table problem");
+}
+```
+
+С помощью метода `Session.describeTable()` можно вывести информацию о структуре таблицы и убедиться, что она успешно создалась:
+
+```java
+private void describeTables() {
+ logger.info("--[ DescribeTables ]--");
+
+ Arrays.asList("series", "seasons", "episodes").forEach(tableName -> {
+ String tablePath = database + '/' + tableName;
+ TableDescription tableDesc = retryCtx.supplyResult(session -> session.describeTable(tablePath))
+ .join().expect("describe table problem");
+
+ List<String> primaryKeys = tableDesc.getPrimaryKeys();
+ logger.info(" table {}", tableName);
+ for (TableColumn column : tableDesc.getColumns()) {
+ boolean isPrimary = primaryKeys.contains(column.getName());
+ logger.info(" {}: {} {}", column.getName(), column.getType(), isPrimary ? " (PK)" : "");
+ }
+ });
+}
+```
+{% include [../steps/03_write_queries.md](../_includes/steps/03_write_queries.md) %}
+
+Фрагмент кода, демонстрирующий выполнение запроса на запись/изменение данных:
+
+```java
+private void upsertSimple() {
+ String query
+ = "UPSERT INTO episodes (series_id, season_id, episode_id, title) "
+ + "VALUES (2, 6, 1, \"TBD\");";
+
+ // Begin new transaction with SerializableRW mode
+ TxControl txControl = TxControl.serializableRw().setCommitTx(true);
+
+ // Executes data query with specified transaction control settings.
+ retryCtx.supplyResult(session -> session.executeDataQuery(query, txControl))
+ .join().expect("execute data query problem");
+}
+```
+
+{% include [steps/04_query_processing.md](../_includes/steps/04_query_processing.md) %}
+
+Для выполнения YQL-запросов используется метод `Session.executeDataQuery()`.
+SDK позволяет в явном виде контролировать выполнение транзакций и настраивать необходимый режим выполнения транзакций с помощью класса `TxControl`.
+
+В фрагменте кода, приведенного ниже, транзакция выполняется с помощью метода `session.executeDataQuery()`. Устанавливается режим выполнения транзакции `TxControl txControl = TxControl.serializableRw().setCommitTx(true);` и флаг автоматического завершения транзакции `setCommitTx(true)`. Тело запроса описано с помощью синтаксиса YQL и как параметр передается методу `executeDataQuery`.
+
+```java
+private void selectSimple() {
+ String query
+ = "SELECT series_id, title, release_date "
+ + "FROM series WHERE series_id = 1;";
+
+ // Begin new transaction with SerializableRW mode
+ TxControl txControl = TxControl.serializableRw().setCommitTx(true);
+
+ // Executes data query with specified transaction control settings.
+ DataQueryResult result = retryCtx.supplyResult(session -> session.executeDataQuery(query, txControl))
+ .join().expect("execute data query");
+
+ logger.info("--[ SelectSimple ]--");
+
+ ResultSetReader rs = result.getResultSet(0);
+ while (rs.next()) {
+ logger.info("read series with id {}, title {} and release_date {}",
+ rs.getColumn("series_id").getUint64(),
+ rs.getColumn("title").getUtf8(),
+ rs.getColumn("release_date").getDate()
+ );
+ }
+}
+```
+
+В результате исполнения запроса формируется объект класса `DataQueryResult`, который может содержать несколько выборок, получаемых методом `getResultSet( <index> )`. Так как запрос содержал только одну команду `SELECT`, то результат содержит только одну выборку под индексом `0`. Приведенный фрагмент кода при запуске выводит на консоль текст:
+
+```bash
+12:06:36.548 INFO App - --[ SelectSimple ]--
+12:06:36.559 INFO App - read series with id 1, title IT Crowd and release_date 2006-02-03
+```
+
+{% include [param_queries.md](../_includes/steps/06_param_queries.md) %}
+
+Фрагмент кода, приведенный ниже, демонстрирует использование параметризованных запросов и класс `Params` для формирования параметров и передачи их методу `executeDataQuery`.
+
+```java
+private void selectWithParams(long seriesID, long seasonID) {
+ String query
+ = "DECLARE $seriesId AS Uint64; "
+ + "DECLARE $seasonId AS Uint64; "
+ + "SELECT sa.title AS season_title, sr.title AS series_title "
+ + "FROM seasons AS sa INNER JOIN series AS sr ON sa.series_id = sr.series_id "
+ + "WHERE sa.series_id = $seriesId AND sa.season_id = $seasonId";
+
+ // Begin new transaction with SerializableRW mode
+ TxControl txControl = TxControl.serializableRw().setCommitTx(true);
+
+ // Type of parameter values should be exactly the same as in DECLARE statements.
+ Params params = Params.of(
+ "$seriesId", PrimitiveValue.uint64(seriesID),
+ "$seasonId", PrimitiveValue.uint64(seasonID)
+ );
+
+ DataQueryResult result = retryCtx.supplyResult(session -> session.executeDataQuery(query, txControl, params))
+ .join().expect("execute data query");
+
+ logger.info("--[ SelectWithParams ] -- ");
+
+ ResultSetReader rs = result.getResultSet(0);
+ while (rs.next()) {
+ logger.info("read season with title {} for series {}",
+ rs.getColumn("season_title").getUtf8(),
+ rs.getColumn("series_title").getUtf8()
+ );
+ }
+}
+```
+
+{% include [scan_query.md](../_includes/steps/08_scan_query.md) %}
+
+```java
+private void scanQueryWithParams(long seriesID, long seasonID) {
+ String query
+ = "DECLARE $seriesId AS Uint64; "
+ + "DECLARE $seasonId AS Uint64; "
+ + "SELECT ep.title AS episode_title, sa.title AS season_title, sr.title AS series_title "
+ + "FROM episodes AS ep "
+ + "JOIN seasons AS sa ON sa.season_id = ep.season_id "
+ + "JOIN series AS sr ON sr.series_id = sa.series_id "
+ + "WHERE sa.series_id = $seriesId AND sa.season_id = $seasonId;";
+
+ // Type of parameter values should be exactly the same as in DECLARE statements.
+ Params params = Params.of(
+ "$seriesId", PrimitiveValue.uint64(seriesID),
+ "$seasonId", PrimitiveValue.uint64(seasonID)
+ );
+
+ logger.info("--[ ExecuteScanQueryWithParams ]--");
+ retryCtx.supplyStatus(session -> {
+ ExecuteScanQuerySettings settings = ExecuteScanQuerySettings.newBuilder().build();
+ return session.executeScanQuery(query, params, settings, rs -> {
+ while (rs.next()) {
+ logger.info("read episode {} of {} for {}",
+ rs.getColumn("episode_title").getUtf8(),
+ rs.getColumn("season_title").getUtf8(),
+ rs.getColumn("series_title").getUtf8()
+ );
+ }
+ });
+ }).join().expect("scan query problem");
+}
+```
+
+{% include [multistep_transactions.md](../_includes/steps/09_multistep_transactions.md) %}
+
+Для обеспечения корректности совместной работы транзакций и контекста ретраев - каждая транзация должна выполняться целиком внутри callback, передаваемого в `SessionRetryContext`. Возврат из callback должен происходить после полного завершения транзакции.
+
+Шаблон кода по использовании сложных транзакций в `SessionRetryContext`
+```java
+private void multiStepTransaction(long seriesID, long seasonID) {
+ retryCtx.supplyStatus(session -> {
+ // Multiple operations with session
+ ...
+
+ // return success status to SessionRetryContext
+ return CompletableFuture.completedFuture(Status.SUCCESS);
+ }).join().expect("multistep transaction problem");
+}
+
+```
+
+Первый шаг — подготовка и выполнение первого запроса:
+
+```java
+ String query1
+ = "DECLARE $seriesId AS Uint64; "
+ + "DECLARE $seasonId AS Uint64; "
+ + "SELECT MIN(first_aired) AS from_date FROM seasons "
+ + "WHERE series_id = $seriesId AND season_id = $seasonId;";
+
+ // Execute first query to get the required values to the client.
+ // Transaction control settings don't set CommitTx flag to keep transaction active
+ // after query execution.
+ TxControl tx1 = TxControl.serializableRw().setCommitTx(false);
+ DataQueryResult res1 = session.executeDataQuery(query1, tx1, Params.of(
+ "$seriesId", PrimitiveValue.uint64(seriesID),
+ "$seasonId", PrimitiveValue.uint64(seasonID)
+ )).join().expect("execute data query problem");
+```
+
+Затем мы можем выполнить некоторую клиентскую обработку полученных данных:
+
+```java
+ // Perform some client logic on returned values
+ ResultSetReader resultSet = res1.getResultSet(0);
+ if (!resultSet.next()) {
+ throw new RuntimeException("not found first_aired");
+ }
+ LocalDate fromDate = resultSet.getColumn("from_date").getDate();
+ LocalDate toDate = fromDate.plusDays(15);
+```
+
+И получить текущий `transaction id` для дальшейшей работы в рамках одной транзакции:
+
+```java
+ // Get active transaction id
+ String txId = res1.getTxId();
+```
+
+Следующий шаг — создание следующего запроса, использующего результаты выполнения кода на стороне клиентского приложения:
+
+```java
+ // Construct next query based on the results of client logic
+ String query2
+ = "DECLARE $seriesId AS Uint64;"
+ + "DECLARE $fromDate AS Date;"
+ + "DECLARE $toDate AS Date;"
+ + "SELECT season_id, episode_id, title, air_date FROM episodes "
+ + "WHERE series_id = $seriesId AND air_date >= $fromDate AND air_date <= $toDate;";
+
+ // Execute second query.
+ // Transaction control settings continues active transaction (tx) and
+ // commits it at the end of second query execution.
+ TxControl tx2 = TxControl.id(txId).setCommitTx(true);
+ DataQueryResult res2 = session.executeDataQuery(query2, tx2, Params.of(
+ "$seriesId", PrimitiveValue.uint64(seriesID),
+ "$fromDate", PrimitiveValue.date(fromDate),
+ "$toDate", PrimitiveValue.date(toDate)
+ )).join().expect("execute data query problem");
+
+ logger.info("--[ MultiStep ]--");
+ ResultSetReader rs = res2.getResultSet(0);
+ while (rs.next()) {
+ logger.info("read episode {} with air date {}",
+ rs.getColumn("title").getUtf8(),
+ rs.getColumn("air_date").getDate()
+ );
+ }
+```
+
+Приведенные фрагменты кода при запуске выводят на консоль текст:
+
+```bash
+12:06:36.850 INFO App - --[ MultiStep ]--
+12:06:36.851 INFO App - read episode Grow Fast or Die Slow with air date 2018-03-25
+12:06:36.851 INFO App - read episode Reorientation with air date 2018-04-01
+12:06:36.851 INFO App - read episode Chief Operating Officer with air date 2018-04-08
+```
+
+{% include [transaction_control.md](../_includes/steps/10_transaction_control.md) %}
+
+Фрагмент кода, демонстрирующий явное использование вызовов `beginTransaction()` и `transaction.Commit()`:
+
+```java
+private void tclTransaction() {
+ retryCtx.supplyStatus(session -> {
+ Transaction transaction = session.beginTransaction(TransactionMode.SERIALIZABLE_READ_WRITE)
+ .join().expect("begin transaction problem");
+
+ String query
+ = "DECLARE $airDate AS Date; "
+ + "UPDATE episodes SET air_date = $airDate WHERE title = \"TBD\";";
+
+ Params params = Params.of("$airDate", PrimitiveValue.date(Instant.now()));
+
+ // Execute data query.
+ // Transaction control settings continues active transaction (tx)
+ TxControl txControl = TxControl.id(transaction).setCommitTx(false);
+ DataQueryResult result = session.executeDataQuery(query, txControl, params)
+ .join().expect("execute date query problem");
+
+ logger.info("get transaction {}", result.getTxId());
+
+ // Commit active transaction (tx)
+ return transaction.commit();
+ }).join().expect("tcl transaction problem");
+}
+```
+
+
diff --git a/ydb/docs/ru/core/reference/ydb-sdk/example/toc_i.yaml b/ydb/docs/ru/core/reference/ydb-sdk/example/toc_i.yaml
index a030cd21a2..259520ff2b 100644
--- a/ydb/docs/ru/core/reference/ydb-sdk/example/toc_i.yaml
+++ b/ydb/docs/ru/core/reference/ydb-sdk/example/toc_i.yaml
@@ -8,7 +8,7 @@ items:
- name: Go
href: go/index.md
- name: Java
- href: example-java.md
+ href: java/index.md
- name: Node.js
href: example-nodejs.md
- name: PHP
diff --git a/ydb/docs/ru/core/reference/ydb-sdk/recipes/session_pool_limit/_includes/java.md b/ydb/docs/ru/core/reference/ydb-sdk/recipes/session_pool_limit/_includes/java.md
new file mode 100644
index 0000000000..402c5e65ba
--- /dev/null
+++ b/ydb/docs/ru/core/reference/ydb-sdk/recipes/session_pool_limit/_includes/java.md
@@ -0,0 +1,7 @@
+```java
+this.tableClient = TableClient.newClient(rpc)
+ // 10 - minimum number of active sessions to keep in the pool during the cleanup
+ // 500 - maximum number of sessions in the pool
+ .sessionPoolSize(10, 500)
+ .build();
+``` \ No newline at end of file
diff --git a/ydb/docs/ru/core/reference/ydb-sdk/recipes/session_pool_limit/index.md b/ydb/docs/ru/core/reference/ydb-sdk/recipes/session_pool_limit/index.md
index 388dca88f1..0377e9c4c1 100644
--- a/ydb/docs/ru/core/reference/ydb-sdk/recipes/session_pool_limit/index.md
+++ b/ydb/docs/ru/core/reference/ydb-sdk/recipes/session_pool_limit/index.md
@@ -17,5 +17,9 @@
{% include [go.md](_includes/go.md) %}
+- Java
+
+
+ {% include [java.md](_includes/java.md) %}
{% endlist %}