From dc2126eda62d7c49f9e8205a9605671e1ae610f2 Mon Sep 17 00:00:00 2001 From: Kirill Kurdyukov Date: Thu, 15 Feb 2024 21:40:16 +0300 Subject: [PATCH 01/12] [Liquibase]: Spring Liquibase application example (#24) --- jdbc/pom.xml | 1 + jdbc/spring-liquibase-app/pom.xml | 146 ++++++++++++++++++ .../ydb/liquibase/LiquibaseApplication.kt | 9 ++ .../tech/ydb/liquibase/model/Employee.kt | 36 +++++ .../repository/EmployeeRepository.kt | 8 + .../src/main/resources/application.properties | 8 + .../src/main/resources/changelog.yaml | 45 ++++++ .../tech/ydb/liquibase/YdbLiquibaseTest.kt | 67 ++++++++ .../src/test/resources/logback.xml | 19 +++ 9 files changed, 339 insertions(+) create mode 100644 jdbc/spring-liquibase-app/pom.xml create mode 100644 jdbc/spring-liquibase-app/src/main/kotlin/tech/ydb/liquibase/LiquibaseApplication.kt create mode 100644 jdbc/spring-liquibase-app/src/main/kotlin/tech/ydb/liquibase/model/Employee.kt create mode 100644 jdbc/spring-liquibase-app/src/main/kotlin/tech/ydb/liquibase/repository/EmployeeRepository.kt create mode 100644 jdbc/spring-liquibase-app/src/main/resources/application.properties create mode 100644 jdbc/spring-liquibase-app/src/main/resources/changelog.yaml create mode 100644 jdbc/spring-liquibase-app/src/test/kotlin/tech/ydb/liquibase/YdbLiquibaseTest.kt create mode 100644 jdbc/spring-liquibase-app/src/test/resources/logback.xml diff --git a/jdbc/pom.xml b/jdbc/pom.xml index 9984f39..b3ef6b1 100644 --- a/jdbc/pom.xml +++ b/jdbc/pom.xml @@ -48,6 +48,7 @@ spring-data-jpa + spring-liquibase-app diff --git a/jdbc/spring-liquibase-app/pom.xml b/jdbc/spring-liquibase-app/pom.xml new file mode 100644 index 0000000..2f15426 --- /dev/null +++ b/jdbc/spring-liquibase-app/pom.xml @@ -0,0 +1,146 @@ + + 4.0.0 + + tech.ydb.jdbc.examples + ydb-jdbc-examples + 1.1.0-SNAPSHOT + + + spring-liquibase-app + Spring Liquibase Example + Basic example for SpringBoot3 and Liquibase + + 17 + 1.9.22 + 0.9.1 + 3.2.1 + 0.9.1 + 4.24.0 + + + + org.springframework.boot + spring-boot-starter-data-jpa + ${spring.boot.version} + + + org.springframework.data + spring-data-commons + ${spring.boot.version} + + + org.jetbrains.kotlin + kotlin-reflect + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin.version} + + + tech.ydb.dialects + hibernate-ydb-dialect + ${hibernate.ydb.dialect.version} + + + tech.ydb.jdbc + ydb-jdbc-driver-shaded + + + tech.ydb.dialects + liquibase-ydb-dialect + ${liquibase.ydb.dialect.version} + + + org.slf4j + slf4j-simple + + + + + org.liquibase + liquibase-core + ${liquibase.core.version} + + + + org.springframework.boot + spring-boot-starter-test + ${spring.boot.version} + test + + + tech.ydb.test + ydb-junit5-support + test + + + org.junit.jupiter + junit-jupiter-api + + + + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/test/kotlin + + + org.apache.maven.plugins + maven-surefire-plugin + + + true + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + compile + + + + test-compile + + test-compile + + + + + + -Xjsr305=strict + + + spring + jpa + + + + + org.jetbrains.kotlin + kotlin-maven-allopen + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-maven-noarg + ${kotlin.version} + + + + + + \ No newline at end of file diff --git a/jdbc/spring-liquibase-app/src/main/kotlin/tech/ydb/liquibase/LiquibaseApplication.kt b/jdbc/spring-liquibase-app/src/main/kotlin/tech/ydb/liquibase/LiquibaseApplication.kt new file mode 100644 index 0000000..3f6db9a --- /dev/null +++ b/jdbc/spring-liquibase-app/src/main/kotlin/tech/ydb/liquibase/LiquibaseApplication.kt @@ -0,0 +1,9 @@ +package tech.ydb.liquibase + +import org.springframework.boot.autoconfigure.SpringBootApplication + +/** + * @author Kirill Kurdyukov + */ +@SpringBootApplication +class LiquibaseApplication \ No newline at end of file diff --git a/jdbc/spring-liquibase-app/src/main/kotlin/tech/ydb/liquibase/model/Employee.kt b/jdbc/spring-liquibase-app/src/main/kotlin/tech/ydb/liquibase/model/Employee.kt new file mode 100644 index 0000000..1cba0d9 --- /dev/null +++ b/jdbc/spring-liquibase-app/src/main/kotlin/tech/ydb/liquibase/model/Employee.kt @@ -0,0 +1,36 @@ +package tech.ydb.liquibase.model + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.Table +import java.time.LocalDate +import java.time.LocalDateTime + +@Entity +@Table(name = "employee") +data class Employee( + @Id + val id: Long, + + @Column(name = "full_name") + val fullName: String, + + @Column + val email: String, + + @Column(name = "hire_date") + val hireDate: LocalDate, + + @Column + val salary: java.math.BigDecimal, + + @Column(name = "is_active") + val isActive: Boolean, + + @Column + val department: String, + + @Column + val age: Int, +) \ No newline at end of file diff --git a/jdbc/spring-liquibase-app/src/main/kotlin/tech/ydb/liquibase/repository/EmployeeRepository.kt b/jdbc/spring-liquibase-app/src/main/kotlin/tech/ydb/liquibase/repository/EmployeeRepository.kt new file mode 100644 index 0000000..2a8b173 --- /dev/null +++ b/jdbc/spring-liquibase-app/src/main/kotlin/tech/ydb/liquibase/repository/EmployeeRepository.kt @@ -0,0 +1,8 @@ +package tech.ydb.liquibase.repository + +import org.springframework.data.repository.CrudRepository +import tech.ydb.liquibase.model.Employee + +interface EmployeeRepository : CrudRepository + +fun EmployeeRepository.findByIdOrNull(id: Long): Employee? = this.findById(id).orElse(null) diff --git a/jdbc/spring-liquibase-app/src/main/resources/application.properties b/jdbc/spring-liquibase-app/src/main/resources/application.properties new file mode 100644 index 0000000..2c5403c --- /dev/null +++ b/jdbc/spring-liquibase-app/src/main/resources/application.properties @@ -0,0 +1,8 @@ +spring.jpa.properties.hibernate.dialect=tech.ydb.hibernate.dialect.YdbDialect + +spring.datasource.driver-class-name=tech.ydb.jdbc.YdbDriver +spring.datasource.url=jdbc:ydb:grpc://localhost:2136/local + +spring.liquibase.change-log=classpath:changelog.yaml + +logging.level.liquibase=DEBUG diff --git a/jdbc/spring-liquibase-app/src/main/resources/changelog.yaml b/jdbc/spring-liquibase-app/src/main/resources/changelog.yaml new file mode 100644 index 0000000..1002193 --- /dev/null +++ b/jdbc/spring-liquibase-app/src/main/resources/changelog.yaml @@ -0,0 +1,45 @@ +databaseChangeLog: + - changeSet: + id: "20230904-1" + author: "yourName" + changes: + - createTable: + tableName: employee + columns: + - column: + name: id + type: bigint + constraints: + primaryKey: true + nullable: false + - column: + name: full_name + type: varchar + - column: + name: email + type: varchar + - column: + name: hire_date + type: date + - column: + name: salary + type: decimal(22,9) + - column: + name: is_active + type: boolean + - column: + name: department + type: varchar + - column: + name: age + type: int + - column: + name: limit_date_password + type: datetime + - createIndex: + indexName: idx_employee_email + tableName: employee + unique: false + columns: + - column: + name: email diff --git a/jdbc/spring-liquibase-app/src/test/kotlin/tech/ydb/liquibase/YdbLiquibaseTest.kt b/jdbc/spring-liquibase-app/src/test/kotlin/tech/ydb/liquibase/YdbLiquibaseTest.kt new file mode 100644 index 0000000..46e4308 --- /dev/null +++ b/jdbc/spring-liquibase-app/src/test/kotlin/tech/ydb/liquibase/YdbLiquibaseTest.kt @@ -0,0 +1,67 @@ +package tech.ydb.liquibase + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.RegisterExtension +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.DynamicPropertyRegistry +import org.springframework.test.context.DynamicPropertySource +import tech.ydb.liquibase.model.Employee +import tech.ydb.liquibase.repository.EmployeeRepository +import tech.ydb.liquibase.repository.findByIdOrNull +import tech.ydb.test.junit5.YdbHelperExtension +import java.math.BigDecimal +import java.time.LocalDate +import java.time.ZoneId +import java.util.* + +/** + * @author Kirill Kurdyukov + */ +@SpringBootTest +class YdbLiquibaseTest { + + companion object { + @JvmField + @RegisterExtension + val ydb = YdbHelperExtension() + + @JvmStatic + @DynamicPropertySource + fun propertySource(registry: DynamicPropertyRegistry) { + registry.add("spring.datasource.url") { + "jdbc:ydb:${if (ydb.useTls()) "grpcs://" else "grpc://"}" + + "${ydb.endpoint()}${ydb.database()}${ydb.authToken()?.let { "?token=$it" } ?: ""}" + } + } + } + + @Autowired + lateinit var employeeRepository: EmployeeRepository + + @Test + fun `migration liquibase and CRUD actions`() { + TimeZone.setDefault(TimeZone.getTimeZone(ZoneId.of("UTC"))) + + val employee = Employee( + 1, + "Kirill Kurdyukov", + "kurdyukov-kir@ydb.tech", + LocalDate.parse("2023-12-20"), + BigDecimal("500000.000000000"), + true, + "YDB AppTeam", + 23 + ) + + employeeRepository.save(employee) + + assertEquals(employee, employeeRepository.findByIdOrNull(employee.id)) + + employeeRepository.delete(employee) + + assertNull(employeeRepository.findByIdOrNull(employee.id)) + } +} \ No newline at end of file diff --git a/jdbc/spring-liquibase-app/src/test/resources/logback.xml b/jdbc/spring-liquibase-app/src/test/resources/logback.xml new file mode 100644 index 0000000..5a56f30 --- /dev/null +++ b/jdbc/spring-liquibase-app/src/test/resources/logback.xml @@ -0,0 +1,19 @@ + + + + + %d %5p %40.40c:%4L - %m%n + + + + + + + + + + + + + + \ No newline at end of file From 520aec588964e0d1d26c05fe6986a785abc4d004 Mon Sep 17 00:00:00 2001 From: Kirill Kurdyukov Date: Fri, 16 Feb 2024 16:56:24 +0300 Subject: [PATCH 02/12] Update changelog.yaml --- jdbc/spring-liquibase-app/src/main/resources/changelog.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdbc/spring-liquibase-app/src/main/resources/changelog.yaml b/jdbc/spring-liquibase-app/src/main/resources/changelog.yaml index 1002193..7d04696 100644 --- a/jdbc/spring-liquibase-app/src/main/resources/changelog.yaml +++ b/jdbc/spring-liquibase-app/src/main/resources/changelog.yaml @@ -1,7 +1,7 @@ databaseChangeLog: - changeSet: - id: "20230904-1" - author: "yourName" + id: "employee" + author: "kurdyukov-kir" changes: - createTable: tableName: employee From f2450260794b16f79a39257ea92e16205054f198 Mon Sep 17 00:00:00 2001 From: KirillKurdyukov Date: Fri, 16 Feb 2024 20:55:02 +0300 Subject: [PATCH 03/12] [Liquibase]: Spring Liquibase application example --- jdbc/spring-liquibase-app/pom.xml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/jdbc/spring-liquibase-app/pom.xml b/jdbc/spring-liquibase-app/pom.xml index 2f15426..8a2c40b 100644 --- a/jdbc/spring-liquibase-app/pom.xml +++ b/jdbc/spring-liquibase-app/pom.xml @@ -50,13 +50,7 @@ tech.ydb.dialects liquibase-ydb-dialect - ${liquibase.ydb.dialect.version} - - - org.slf4j - slf4j-simple - - + 1.0.0-SNAPSHOT org.liquibase From 619483c3dbc342d4dc54f7ac5d55caf426309014 Mon Sep 17 00:00:00 2001 From: KirillKurdyukov Date: Mon, 19 Feb 2024 13:31:00 +0300 Subject: [PATCH 04/12] [Liquibase]: Update version in SpringBoot Liquibase example --- jdbc/spring-liquibase-app/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdbc/spring-liquibase-app/pom.xml b/jdbc/spring-liquibase-app/pom.xml index 8a2c40b..1547093 100644 --- a/jdbc/spring-liquibase-app/pom.xml +++ b/jdbc/spring-liquibase-app/pom.xml @@ -50,7 +50,7 @@ tech.ydb.dialects liquibase-ydb-dialect - 1.0.0-SNAPSHOT + 0.9.3 org.liquibase From 35ce0d21bf31e2fbc0219cafd21ade5b9de3e4a2 Mon Sep 17 00:00:00 2001 From: Kirill Kurdyukov Date: Mon, 18 Mar 2024 16:22:16 +0300 Subject: [PATCH 05/12] Update versions in SpringBoot examples (#25) --- jdbc/spring-data-jpa-v5/pom.xml | 2 +- jdbc/spring-data-jpa/pom.xml | 2 +- jdbc/spring-liquibase-app/pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jdbc/spring-data-jpa-v5/pom.xml b/jdbc/spring-data-jpa-v5/pom.xml index 86c1e36..bba7163 100644 --- a/jdbc/spring-data-jpa-v5/pom.xml +++ b/jdbc/spring-data-jpa-v5/pom.xml @@ -11,7 +11,7 @@ Basic example for SpringBoot3 and Hibernate 6 1.9.22 - 0.9.1 + 0.9.2 2.5.7 diff --git a/jdbc/spring-data-jpa/pom.xml b/jdbc/spring-data-jpa/pom.xml index 30294b5..d883b09 100644 --- a/jdbc/spring-data-jpa/pom.xml +++ b/jdbc/spring-data-jpa/pom.xml @@ -12,7 +12,7 @@ 17 1.9.22 - 0.9.1 + 0.9.2 3.2.1 diff --git a/jdbc/spring-liquibase-app/pom.xml b/jdbc/spring-liquibase-app/pom.xml index 1547093..af75ac1 100644 --- a/jdbc/spring-liquibase-app/pom.xml +++ b/jdbc/spring-liquibase-app/pom.xml @@ -50,7 +50,7 @@ tech.ydb.dialects liquibase-ydb-dialect - 0.9.3 + 0.9.7 org.liquibase From 694521dd04886cd71b697d2723b6dda507dcedba Mon Sep 17 00:00:00 2001 From: Alexandr Gorshenin Date: Wed, 20 Mar 2024 11:27:12 +0000 Subject: [PATCH 06/12] Basic example for QueryService --- pom.xml | 3 +- query-example/pom.xml | 88 +++++ .../src/main/java/tech/ydb/example/App.java | 374 ++++++++++++++++++ .../java/tech/ydb/example/SeriesData.java | 114 ++++++ .../java/tech/ydb/example/model/Episode.java | 40 ++ .../java/tech/ydb/example/model/Season.java | 40 ++ .../java/tech/ydb/example/model/Series.java | 34 ++ query-example/src/main/resources/log4j2.xml | 27 ++ .../tech/ydb/example/BasicExampleTest.java | 30 ++ 9 files changed, 749 insertions(+), 1 deletion(-) create mode 100644 query-example/pom.xml create mode 100644 query-example/src/main/java/tech/ydb/example/App.java create mode 100644 query-example/src/main/java/tech/ydb/example/SeriesData.java create mode 100644 query-example/src/main/java/tech/ydb/example/model/Episode.java create mode 100644 query-example/src/main/java/tech/ydb/example/model/Season.java create mode 100644 query-example/src/main/java/tech/ydb/example/model/Series.java create mode 100644 query-example/src/main/resources/log4j2.xml create mode 100644 query-example/src/test/java/tech/ydb/example/BasicExampleTest.java diff --git a/pom.xml b/pom.xml index 1f1188a..8a72253 100644 --- a/pom.xml +++ b/pom.xml @@ -18,13 +18,14 @@ 2.22.1 1.82 - 2.1.11 + 2.2.0-SNAPSHOT auth secondary_index basic_example + query-example ydb-cookbook url-shortener-demo jdbc diff --git a/query-example/pom.xml b/query-example/pom.xml new file mode 100644 index 0000000..b95c969 --- /dev/null +++ b/query-example/pom.xml @@ -0,0 +1,88 @@ + + + 4.0.0 + + + tech.ydb.examples + ydb-sdk-examples + 1.1.0-SNAPSHOT + + + ydb-query-example + YDB QueryClient basic example + Simple example of usage QueryClient of Java SDK for YDB + + + 5.10.1 + + + + + tech.ydb + ydb-sdk-query + + + tech.ydb + ydb-sdk-topic + + + tech.ydb.auth + yc-auth-provider + + + + org.apache.logging.log4j + log4j-slf4j-impl + + + + tech.ydb.test + ydb-junit5-support + test + + + + org.junit.jupiter + junit-jupiter-api + ${junit5.version} + test + + + + + ydb-basic-example + + + + org.apache.maven.plugins + maven-dependency-plugin + + + + org.apache.maven.plugins + maven-jar-plugin + + + + true + libs/ + tech.ydb.example.App + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + cr.yandex/yc/yandex-docker-local-ydb:trunk + true + 1 + + + + + + diff --git a/query-example/src/main/java/tech/ydb/example/App.java b/query-example/src/main/java/tech/ydb/example/App.java new file mode 100644 index 0000000..bab6d2b --- /dev/null +++ b/query-example/src/main/java/tech/ydb/example/App.java @@ -0,0 +1,374 @@ +package tech.ydb.example; + +import java.io.IOException; +import java.time.Instant; +import java.time.LocalDate; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import tech.ydb.auth.iam.CloudAuthHelper; +import tech.ydb.core.Status; +import tech.ydb.core.grpc.GrpcTransport; +import tech.ydb.query.QueryClient; +import tech.ydb.query.QueryStream; +import tech.ydb.query.QueryTransaction; +import tech.ydb.query.QueryTx; +import tech.ydb.query.tools.QueryReader; +import tech.ydb.query.tools.SessionRetryContext; +import tech.ydb.table.query.Params; +import tech.ydb.table.result.ResultSetReader; +import tech.ydb.table.values.ListType; +import tech.ydb.table.values.ListValue; +import tech.ydb.table.values.PrimitiveType; +import tech.ydb.table.values.PrimitiveValue; +import tech.ydb.table.values.StructType; + + +public final class App implements Runnable, AutoCloseable { + private static final Logger logger = LoggerFactory.getLogger(App.class); + + private final GrpcTransport transport; + private final QueryClient queryClient; + private final SessionRetryContext retryCtx; + + App(String connectionString) { + this.transport = GrpcTransport.forConnectionString(connectionString) + .withAuthProvider(CloudAuthHelper.getAuthProviderFromEnviron()) + .build(); + this.queryClient = QueryClient.newClient(transport).build(); + this.retryCtx = SessionRetryContext.create(queryClient).build(); + } + + @Override + public void run() { + createTables(); + upsertTablesData(); + + upsertSimple(); + + selectSimple(); + selectWithParams(1, 2); + asyncSelectRead(2, 1); + + multiStepTransaction(2, 5); + tclTransaction(); + + dropTables(); + } + + @Override + public void close() { + queryClient.close(); + transport.close(); + } + + private void createTables() { + retryCtx.supplyResult(session -> session.createQuery("" + + "CREATE TABLE series (" + + " series_id UInt64," + + " title Text," + + " series_info Text," + + " release_date Date," + + " PRIMARY KEY(series_id)" + + ")", QueryTx.NONE).execute() + ).join().getStatus().expectSuccess("Can't create table series"); + + retryCtx.supplyResult(session -> session.createQuery("" + + "CREATE TABLE seasons (" + + " series_id UInt64," + + " season_id UInt64," + + " title Text," + + " first_aired Date," + + " last_aired Date," + + " PRIMARY KEY(series_id, season_id)" + + ")", QueryTx.NONE).execute() + ).join().getStatus().expectSuccess("Can't create table seasons"); + + retryCtx.supplyResult(session -> session.createQuery("" + + "CREATE TABLE episodes (" + + " series_id UInt64," + + " season_id UInt64," + + " episode_id UInt64," + + " title Text," + + " air_date Date," + + " PRIMARY KEY(series_id, season_id, episode_id)" + + ")", QueryTx.NONE).execute() + ).join().getStatus().expectSuccess("Can't create table episodes"); + } + + private void upsertTablesData() { + // Create type for struct of series + StructType seriesType = StructType.of( + "series_id", PrimitiveType.Uint64, + "title", PrimitiveType.Text, + "release_date", PrimitiveType.Date, + "series_info", PrimitiveType.Text + ); + // Create and fill list of series + ListValue seriesData = ListType.of(seriesType).newValue( + SeriesData.SERIES.stream().map(series -> seriesType.newValue( + "series_id", PrimitiveValue.newUint64(series.seriesID()), + "title", PrimitiveValue.newText(series.title()), + "release_date", PrimitiveValue.newDate(series.releaseDate()), + "series_info", PrimitiveValue.newText(series.seriesInfo()) + )).collect(Collectors.toList()) + ); + + // Upsert list of series to table + retryCtx.supplyResult(session -> session.createQuery( + "UPSERT INTO series SELECT * FROM AS_TABLE($values)", + QueryTx.SERIALIZABLE_RW, + Params.of("$values", seriesData) + ).execute()).join().getStatus().expectSuccess("upsert problem"); + + + // Create type for struct of season + StructType seasonType = StructType.of( + "series_id", PrimitiveType.Uint64, + "season_id", PrimitiveType.Uint64, + "title", PrimitiveType.Text, + "first_aired", PrimitiveType.Date, + "last_aired", PrimitiveType.Date + ); + // Create and fill list of seasons + ListValue seasonsData = ListType.of(seasonType).newValue( + SeriesData.SEASONS.stream().map(season -> seasonType.newValue( + "series_id", PrimitiveValue.newUint64(season.seriesID()), + "season_id", PrimitiveValue.newUint64(season.seasonID()), + "title", PrimitiveValue.newText(season.title()), + "first_aired", PrimitiveValue.newDate(season.firstAired()), + "last_aired", PrimitiveValue.newDate(season.lastAired()) + )).collect(Collectors.toList()) + ); + + // Upsert list of seasons to table + retryCtx.supplyResult(session -> session.createQuery( + "UPSERT INTO seasons SELECT * FROM AS_TABLE($values)", + QueryTx.SERIALIZABLE_RW, + Params.of("$values", seasonsData) + ).execute()).join().getStatus().expectSuccess("upsert problem"); + + + // Create type for struct of episode + StructType episodeType = StructType.of( + "series_id", PrimitiveType.Uint64, + "season_id", PrimitiveType.Uint64, + "episode_id", PrimitiveType.Uint64, + "title", PrimitiveType.Text, + "air_date", PrimitiveType.Date + ); + // Create and fill list of episodes + ListValue episodesData = ListType.of(episodeType).newValue( + SeriesData.EPISODES.stream().map(episode -> episodeType.newValue( + "series_id", PrimitiveValue.newUint64(episode.seriesID()), + "season_id", PrimitiveValue.newUint64(episode.seasonID()), + "episode_id", PrimitiveValue.newUint64(episode.episodeID()), + "title", PrimitiveValue.newText(episode.title()), + "air_date", PrimitiveValue.newDate(episode.airDate()) + )).collect(Collectors.toList()) + ); + + // Upsert list of series to episodes + retryCtx.supplyResult(session -> session.createQuery( + "UPSERT INTO episodes SELECT * FROM AS_TABLE($values)", + QueryTx.SERIALIZABLE_RW, + Params.of("$values", episodesData) + ).execute()).join().getStatus().expectSuccess("upsert problem"); + } + + private void upsertSimple() { + String query + = "UPSERT INTO episodes (series_id, season_id, episode_id, title) " + + "VALUES (2, 6, 1, \"TBD\");"; + + // Executes data query with specified transaction control settings. + retryCtx.supplyResult(session -> session.createQuery(query, QueryTx.SERIALIZABLE_RW).execute()) + .join().getValue(); + } + + private void selectSimple() { + String query + = "SELECT series_id, title, release_date " + + "FROM series WHERE series_id = 1;"; + + // Executes data query with specified transaction control settings. + QueryReader result = retryCtx.supplyResult( + session -> QueryReader.readFrom(session.createQuery(query, QueryTx.SERIALIZABLE_RW)) + ).join().getValue(); + + 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").getText(), + rs.getColumn("release_date").getDate() + ); + } + } + + 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"; + + // Type of parameter values should be exactly the same as in DECLARE statements. + Params params = Params.of( + "$seriesId", PrimitiveValue.newUint64(seriesID), + "$seasonId", PrimitiveValue.newUint64(seasonID) + ); + + QueryReader result = retryCtx.supplyResult( + session -> QueryReader.readFrom(session.createQuery(query, QueryTx.SNAPSHOT_RO, params)) + ).join().getValue(); + + logger.info("--[ SelectWithParams ] -- "); + + ResultSetReader rs = result.getResultSet(0); + while (rs.next()) { + logger.info("read season with title {} for series {}", + rs.getColumn("season_title").getText(), + rs.getColumn("series_title").getText() + ); + } + } + + private void asyncSelectRead(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.newUint64(seriesID), + "$seasonId", PrimitiveValue.newUint64(seasonID) + ); + + logger.info("--[ ExecuteAsyncQueryWithParams ]--"); + retryCtx.supplyResult(session -> { + QueryStream asyncQuery = session.createQuery(query, QueryTx.SNAPSHOT_RO, params); + return asyncQuery.execute(part -> { + ResultSetReader rs = part.getResultSetReader(); + logger.info("read {} rows of result set {}", rs.getRowCount(), part.getResultSetIndex()); + while (rs.next()) { + logger.info("read episode {} of {} for {}", + rs.getColumn("episode_title").getText(), + rs.getColumn("season_title").getText(), + rs.getColumn("series_title").getText() + ); + } + }); + }).join().getStatus().expectSuccess("execute query problem"); + } + + private void multiStepTransaction(long seriesID, long seasonID) { + retryCtx.supplyStatus(session -> { + QueryTransaction transaction = session.createNewTransaction(QueryTx.SNAPSHOT_RO); + 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 start a new transaction + QueryReader res1 = QueryReader.readFrom(transaction.createQuery(query1, Params.of( + "$seriesId", PrimitiveValue.newUint64(seriesID), + "$seasonId", PrimitiveValue.newUint64(seasonID) + ))).join().getValue(); + + // 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); + + // Get active transaction id + logger.info("started new transaction {}", transaction.getId()); + + // 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 with commit at end. + QueryReader res2 = QueryReader.readFrom(transaction.createQueryWithCommit(query2, Params.of( + "$seriesId", PrimitiveValue.newUint64(seriesID), + "$fromDate", PrimitiveValue.newDate(fromDate), + "$toDate", PrimitiveValue.newDate(toDate) + ))).join().getValue(); + + logger.info("--[ MultiStep ]--"); + ResultSetReader rs = res2.getResultSet(0); + while (rs.next()) { + logger.info("read episode {} with air date {}", + rs.getColumn("title").getText(), + rs.getColumn("air_date").getDate() + ); + } + + return CompletableFuture.completedFuture(Status.SUCCESS); + }).join().expectSuccess("multistep transaction problem"); + } + + private void tclTransaction() { + retryCtx.supplyResult(session -> { + QueryTransaction transaction = session.beginTransaction(QueryTx.SERIALIZABLE_RW) + .join().getValue(); + + String query + = "DECLARE $airDate AS Date; " + + "UPDATE episodes SET air_date = $airDate WHERE title = \"TBD\";"; + + Params params = Params.of("$airDate", PrimitiveValue.newDate(Instant.now())); + + // Execute data query. + // Transaction control settings continues active transaction (tx) + QueryReader reader = QueryReader.readFrom(transaction.createQuery(query, params)) + .join().getValue(); + + logger.info("get transaction {}", transaction.getId()); + + // Commit active transaction (tx) + return transaction.commit(); + }).join().getStatus().expectSuccess("tcl transaction problem"); + } + + private void dropTables() { + retryCtx.supplyResult(session -> session.createQuery("DROP TABLE episodes;", QueryTx.NONE).execute()) + .join().getStatus().expectSuccess("drop table episodes problem"); + retryCtx.supplyResult(session -> session.createQuery("DROP TABLE seasons;", QueryTx.NONE).execute()) + .join().getStatus().expectSuccess("drop table seasons problem"); + retryCtx.supplyResult(session -> session.createQuery("DROP TABLE series;", QueryTx.NONE).execute()) + .join().getStatus().expectSuccess("drop table series problem"); + } + + public static void main(String[] args) throws IOException { + if (args.length != 1) { + System.err.println("Usage: java -jar ydb-basic-example.jar "); + return; + } + + try (App app = new App(args[0])) { + app.run(); + } catch (Exception e) { + logger.error("app problem", e); + } + } +} diff --git a/query-example/src/main/java/tech/ydb/example/SeriesData.java b/query-example/src/main/java/tech/ydb/example/SeriesData.java new file mode 100644 index 0000000..f047a2d --- /dev/null +++ b/query-example/src/main/java/tech/ydb/example/SeriesData.java @@ -0,0 +1,114 @@ +package tech.ydb.example; + +import java.time.Instant; +import java.util.Arrays; +import java.util.List; + +import tech.ydb.example.model.Episode; +import tech.ydb.example.model.Season; +import tech.ydb.example.model.Series; + + +final class SeriesData { + public static final List SERIES = Arrays.asList( + new Series( + 1, "IT Crowd", date("2006-02-03"), + "The IT Crowd is a British sitcom produced by Channel 4, written by Graham Linehan, produced by " + + "Ash Atalla and starring Chris O'Dowd, Richard Ayoade, Katherine Parkinson, and Matt Berry."), + new Series( + 2, "Silicon Valley", date("2014-04-06"), + "Silicon Valley is an American comedy television series created by Mike Judge, John Altschuler and " + + "Dave Krinsky. The series focuses on five young men who founded a startup company in Silicon Valley.") + ); + + public static final List SEASONS = Arrays.asList( + new Season(1, 1, "Season 1", date("2006-02-03"), date("2006-03-03")), + new Season(1, 2, "Season 2", date("2007-08-24"), date("2007-09-28")), + new Season(1, 3, "Season 3", date("2008-11-21"), date("2008-12-26")), + new Season(1, 4, "Season 4", date("2010-06-25"), date("2010-07-30")), + new Season(2, 1, "Season 1", date("2014-04-06"), date("2014-06-01")), + new Season(2, 2, "Season 2", date("2015-04-12"), date("2015-06-14")), + new Season(2, 3, "Season 3", date("2016-04-24"), date("2016-06-26")), + new Season(2, 4, "Season 4", date("2017-04-23"), date("2017-06-25")), + new Season(2, 5, "Season 5", date("2018-03-25"), date("2018-05-13")) + ); + + public static final List EPISODES = Arrays.asList( + new Episode(1, 1, 1, "Yesterday's Jam", date("2006-02-03")), + new Episode(1, 1, 2, "Calamity Jen", date("2006-02-03")), + new Episode(1, 1, 3, "Fifty-Fifty", date("2006-02-10")), + new Episode(1, 1, 4, "The Red Door", date("2006-02-17")), + new Episode(1, 1, 5, "The Haunting of Bill Crouse", date("2006-02-24")), + new Episode(1, 1, 6, "Aunt Irma Visits", date("2006-03-03")), + new Episode(1, 2, 1, "The Work Outing", date("2006-08-24")), + new Episode(1, 2, 2, "Return of the Golden Child", date("2007-08-31")), + new Episode(1, 2, 3, "Moss and the German", date("2007-09-07")), + new Episode(1, 2, 4, "The Dinner Party", date("2007-09-14")), + new Episode(1, 2, 5, "Smoke and Mirrors", date("2007-09-21")), + new Episode(1, 2, 6, "Men Without Women", date("2007-09-28")), + new Episode(1, 3, 1, "From Hell", date("2008-11-21")), + new Episode(1, 3, 2, "Are We Not Men?", date("2008-11-28")), + new Episode(1, 3, 3, "Tramps Like Us", date("2008-12-05")), + new Episode(1, 3, 4, "The Speech", date("2008-12-12")), + new Episode(1, 3, 5, "Friendface", date("2008-12-19")), + new Episode(1, 3, 6, "Calendar Geeks", date("2008-12-26")), + new Episode(1, 4, 1, "Jen The Fredo", date("2010-06-25")), + new Episode(1, 4, 2, "The Final Countdown", date("2010-07-02")), + new Episode(1, 4, 3, "Something Happened", date("2010-07-09")), + new Episode(1, 4, 4, "Italian For Beginners", date("2010-07-16")), + new Episode(1, 4, 5, "Bad Boys", date("2010-07-23")), + new Episode(1, 4, 6, "Reynholm vs Reynholm", date("2010-07-30")), + new Episode(2, 1, 1, "Minimum Viable Product", date("2014-04-06")), + new Episode(2, 1, 2, "The Cap Table", date("2014-04-13")), + new Episode(2, 1, 3, "Articles of Incorporation", date("2014-04-20")), + new Episode(2, 1, 4, "Fiduciary Duties", date("2014-04-27")), + new Episode(2, 1, 5, "Signaling Risk", date("2014-05-04")), + new Episode(2, 1, 6, "Third Party Insourcing", date("2014-05-11")), + new Episode(2, 1, 7, "Proof of Concept", date("2014-05-18")), + new Episode(2, 1, 8, "Optimal Tip-to-Tip Efficiency", date("2014-06-01")), + new Episode(2, 2, 1, "Sand Hill Shuffle", date("2015-04-12")), + new Episode(2, 2, 2, "Runaway Devaluation", date("2015-04-19")), + new Episode(2, 2, 3, "Bad Money", date("2015-04-26")), + new Episode(2, 2, 4, "The Lady", date("2015-05-03")), + new Episode(2, 2, 5, "Server Space", date("2015-05-10")), + new Episode(2, 2, 6, "Homicide", date("2015-05-17")), + new Episode(2, 2, 7, "Adult Content", date("2015-05-24")), + new Episode(2, 2, 8, "White Hat/Black Hat", date("2015-05-31")), + new Episode(2, 2, 9, "Binding Arbitration", date("2015-06-07")), + new Episode(2, 2, 10, "Two Days of the Condor", date("2015-06-14")), + new Episode(2, 3, 1, "Founder Friendly", date("2016-04-24")), + new Episode(2, 3, 2, "Two in the Box", date("2016-05-01")), + new Episode(2, 3, 3, "Meinertzhagen's Haversack", date("2016-05-08")), + new Episode(2, 3, 4, "Maleant Data Systems Solutions", date("2016-05-15")), + new Episode(2, 3, 5, "The Empty Chair", date("2016-05-22")), + new Episode(2, 3, 6, "Bachmanity Insanity", date("2016-05-29")), + new Episode(2, 3, 7, "To Build a Better Beta", date("2016-06-05")), + new Episode(2, 3, 8, "Bachman's Earnings Over-Ride", date("2016-06-12")), + new Episode(2, 3, 9, "Daily Active Users", date("2016-06-19")), + new Episode(2, 3, 10, "The Uptick", date("2016-06-26")), + new Episode(2, 4, 1, "Success Failure", date("2017-04-23")), + new Episode(2, 4, 2, "Terms of Service", date("2017-04-30")), + new Episode(2, 4, 3, "Intellectual Property", date("2017-05-07")), + new Episode(2, 4, 4, "Teambuilding Exercise", date("2017-05-14")), + new Episode(2, 4, 5, "The Blood Boy", date("2017-05-21")), + new Episode(2, 4, 6, "Customer Service", date("2017-05-28")), + new Episode(2, 4, 7, "The Patent Troll", date("2017-06-04")), + new Episode(2, 4, 8, "The Keenan Vortex", date("2017-06-11")), + new Episode(2, 4, 9, "Hooli-Con", date("2017-06-18")), + new Episode(2, 4, 10, "Server Error", date("2017-06-25")), + new Episode(2, 5, 1, "Grow Fast or Die Slow", date("2018-03-25")), + new Episode(2, 5, 2, "Reorientation", date("2018-04-01")), + new Episode(2, 5, 3, "Chief Operating Officer", date("2018-04-08")), + new Episode(2, 5, 4, "Tech Evangelist", date("2018-04-15")), + new Episode(2, 5, 5, "Facial Recognition", date("2018-04-22")), + new Episode(2, 5, 6, "Artificial Emotional Intelligence", date("2018-04-29")), + new Episode(2, 5, 7, "Initial Coin Offering", date("2018-05-06")), + new Episode(2, 5, 8, "Fifty-One Percent", date("2018-05-13")) + ); + + private SeriesData() { } + + private static Instant date(String str) { + return Instant.parse(str + "T00:00:00Z"); + } +} diff --git a/query-example/src/main/java/tech/ydb/example/model/Episode.java b/query-example/src/main/java/tech/ydb/example/model/Episode.java new file mode 100644 index 0000000..0c68ef7 --- /dev/null +++ b/query-example/src/main/java/tech/ydb/example/model/Episode.java @@ -0,0 +1,40 @@ +package tech.ydb.example.model; + +import java.time.Instant; + + +public class Episode { + private final long seriesID; + private final long seasonID; + private final long episodeID; + private final String title; + private final Instant airDate; + + public Episode(long seriesID, long seasonID, long episodeID, String title, Instant airDate) { + this.seriesID = seriesID; + this.seasonID = seasonID; + this.episodeID = episodeID; + this.title = title; + this.airDate = airDate; + } + + public long seriesID() { + return seriesID; + } + + public long seasonID() { + return seasonID; + } + + public long episodeID() { + return episodeID; + } + + public String title() { + return title; + } + + public Instant airDate() { + return airDate; + } +} diff --git a/query-example/src/main/java/tech/ydb/example/model/Season.java b/query-example/src/main/java/tech/ydb/example/model/Season.java new file mode 100644 index 0000000..eeb512d --- /dev/null +++ b/query-example/src/main/java/tech/ydb/example/model/Season.java @@ -0,0 +1,40 @@ +package tech.ydb.example.model; + +import java.time.Instant; + + +public class Season { + private final long seriesID; + private final long seasonID; + private final String title; + private final Instant firstAired; + private final Instant lastAired; + + public Season(long seriesID, long seasonID, String title, Instant firstAired, Instant lastAired) { + this.seriesID = seriesID; + this.seasonID = seasonID; + this.title = title; + this.firstAired = firstAired; + this.lastAired = lastAired; + } + + public long seriesID() { + return this.seriesID; + } + + public long seasonID() { + return this.seasonID; + } + + public String title() { + return this.title; + } + + public Instant firstAired() { + return this.firstAired; + } + + public Instant lastAired() { + return this.lastAired; + } +} diff --git a/query-example/src/main/java/tech/ydb/example/model/Series.java b/query-example/src/main/java/tech/ydb/example/model/Series.java new file mode 100644 index 0000000..d074c28 --- /dev/null +++ b/query-example/src/main/java/tech/ydb/example/model/Series.java @@ -0,0 +1,34 @@ +package tech.ydb.example.model; + +import java.time.Instant; + + +public class Series { + private final long seriesID; + private final String title; + private final Instant releaseDate; + private final String seriesInfo; + + public Series(long seriesID, String title, Instant releaseDate, String seriesInfo) { + this.seriesID = seriesID; + this.title = title; + this.releaseDate = releaseDate; + this.seriesInfo = seriesInfo; + } + + public long seriesID() { + return seriesID; + } + + public String title() { + return title; + } + + public Instant releaseDate() { + return releaseDate; + } + + public String seriesInfo() { + return seriesInfo; + } +} diff --git a/query-example/src/main/resources/log4j2.xml b/query-example/src/main/resources/log4j2.xml new file mode 100644 index 0000000..cdcbde9 --- /dev/null +++ b/query-example/src/main/resources/log4j2.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/query-example/src/test/java/tech/ydb/example/BasicExampleTest.java b/query-example/src/test/java/tech/ydb/example/BasicExampleTest.java new file mode 100644 index 0000000..8d162a1 --- /dev/null +++ b/query-example/src/test/java/tech/ydb/example/BasicExampleTest.java @@ -0,0 +1,30 @@ +package tech.ydb.example; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import tech.ydb.test.junit5.YdbHelperExtension; + +/** + * + * @author Aleksandr Gorshenin + */ +public class BasicExampleTest { + @RegisterExtension + private static final YdbHelperExtension ydb = new YdbHelperExtension(); + + private static String connectionString() { + StringBuilder sb = new StringBuilder(); + sb.append(ydb.useTls() ? "grpcs://" : "grpc://" ); + sb.append(ydb.endpoint()); + sb.append(ydb.database()); + return sb.toString(); + } + + @Test + public void testBasicApp() { + App app = new App(connectionString()); + app.run(); + app.close(); + } +} From 2c6fd7433854659b1becb1b596f7683ba0037418 Mon Sep 17 00:00:00 2001 From: Alexandr Gorshenin Date: Mon, 25 Mar 2024 14:28:48 +0000 Subject: [PATCH 07/12] Update usage of deprecated transactions --- .../src/main/java/tech/ydb/example/App.java | 17 +++++----- .../src/main/java/tech/ydb/example/App.java | 32 +++++++++---------- .../examples/simple/ComplexTransaction.java | 20 +++++------- 3 files changed, 32 insertions(+), 37 deletions(-) diff --git a/basic_example/src/main/java/tech/ydb/example/App.java b/basic_example/src/main/java/tech/ydb/example/App.java index f515841..05d1c8e 100644 --- a/basic_example/src/main/java/tech/ydb/example/App.java +++ b/basic_example/src/main/java/tech/ydb/example/App.java @@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory; import tech.ydb.auth.iam.CloudAuthHelper; +import tech.ydb.common.transaction.TxMode; import tech.ydb.core.Status; import tech.ydb.core.grpc.GrpcReadStream; import tech.ydb.core.grpc.GrpcTransport; @@ -24,7 +25,7 @@ import tech.ydb.table.result.ResultSetReader; import tech.ydb.table.settings.BulkUpsertSettings; import tech.ydb.table.settings.ExecuteScanQuerySettings; -import tech.ydb.table.transaction.Transaction; +import tech.ydb.table.transaction.TableTransaction; import tech.ydb.table.transaction.TxControl; import tech.ydb.table.values.ListType; import tech.ydb.table.values.ListValue; @@ -303,6 +304,7 @@ private void scanQueryWithParams(long seriesID, long seasonID) { private void multiStepTransaction(long seriesID, long seasonID) { retryCtx.supplyStatus(session -> { + TableTransaction transaction = session.createNewTransaction(TxMode.SERIALIZABLE_RW); String query1 = "DECLARE $seriesId AS Uint64; " + "DECLARE $seasonId AS Uint64; " @@ -312,8 +314,7 @@ private void multiStepTransaction(long seriesID, long 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( + DataQueryResult res1 = transaction.executeDataQuery(query1, Params.of( "$seriesId", PrimitiveValue.newUint64(seriesID), "$seasonId", PrimitiveValue.newUint64(seasonID) )).join().getValue(); @@ -327,7 +328,7 @@ private void multiStepTransaction(long seriesID, long seasonID) { LocalDate toDate = fromDate.plusDays(15); // Get active transaction id - String txId = res1.getTxId(); + logger.info("got transaction id {}", transaction.getId()); // Construct next query based on the results of client logic String query2 @@ -340,8 +341,7 @@ private void multiStepTransaction(long seriesID, long seasonID) { // 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( + DataQueryResult res2 = transaction.executeDataQueryAndCommit(query2, Params.of( "$seriesId", PrimitiveValue.newUint64(seriesID), "$fromDate", PrimitiveValue.newDate(fromDate), "$toDate", PrimitiveValue.newDate(toDate) @@ -362,7 +362,7 @@ private void multiStepTransaction(long seriesID, long seasonID) { private void tclTransaction() { retryCtx.supplyStatus(session -> { - Transaction transaction = session.beginTransaction(Transaction.Mode.SERIALIZABLE_READ_WRITE) + TableTransaction transaction = session.beginTransaction(TxMode.SERIALIZABLE_RW) .join().getValue(); String query @@ -373,8 +373,7 @@ private void tclTransaction() { // Execute data query. // Transaction control settings continues active transaction (tx) - TxControl txControl = TxControl.id(transaction).setCommitTx(false); - DataQueryResult result = session.executeDataQuery(query, txControl, params) + DataQueryResult result = transaction.executeDataQuery(query, params) .join().getValue(); logger.info("get transaction {}", result.getTxId()); diff --git a/query-example/src/main/java/tech/ydb/example/App.java b/query-example/src/main/java/tech/ydb/example/App.java index bab6d2b..58ff312 100644 --- a/query-example/src/main/java/tech/ydb/example/App.java +++ b/query-example/src/main/java/tech/ydb/example/App.java @@ -10,12 +10,12 @@ import org.slf4j.LoggerFactory; import tech.ydb.auth.iam.CloudAuthHelper; +import tech.ydb.common.transaction.TxMode; import tech.ydb.core.Status; import tech.ydb.core.grpc.GrpcTransport; import tech.ydb.query.QueryClient; import tech.ydb.query.QueryStream; import tech.ydb.query.QueryTransaction; -import tech.ydb.query.QueryTx; import tech.ydb.query.tools.QueryReader; import tech.ydb.query.tools.SessionRetryContext; import tech.ydb.table.query.Params; @@ -73,7 +73,7 @@ private void createTables() { + " series_info Text," + " release_date Date," + " PRIMARY KEY(series_id)" - + ")", QueryTx.NONE).execute() + + ")", TxMode.NONE).execute() ).join().getStatus().expectSuccess("Can't create table series"); retryCtx.supplyResult(session -> session.createQuery("" @@ -84,7 +84,7 @@ private void createTables() { + " first_aired Date," + " last_aired Date," + " PRIMARY KEY(series_id, season_id)" - + ")", QueryTx.NONE).execute() + + ")", TxMode.NONE).execute() ).join().getStatus().expectSuccess("Can't create table seasons"); retryCtx.supplyResult(session -> session.createQuery("" @@ -95,7 +95,7 @@ private void createTables() { + " title Text," + " air_date Date," + " PRIMARY KEY(series_id, season_id, episode_id)" - + ")", QueryTx.NONE).execute() + + ")", TxMode.NONE).execute() ).join().getStatus().expectSuccess("Can't create table episodes"); } @@ -120,7 +120,7 @@ private void upsertTablesData() { // Upsert list of series to table retryCtx.supplyResult(session -> session.createQuery( "UPSERT INTO series SELECT * FROM AS_TABLE($values)", - QueryTx.SERIALIZABLE_RW, + TxMode.SERIALIZABLE_RW, Params.of("$values", seriesData) ).execute()).join().getStatus().expectSuccess("upsert problem"); @@ -147,7 +147,7 @@ private void upsertTablesData() { // Upsert list of seasons to table retryCtx.supplyResult(session -> session.createQuery( "UPSERT INTO seasons SELECT * FROM AS_TABLE($values)", - QueryTx.SERIALIZABLE_RW, + TxMode.SERIALIZABLE_RW, Params.of("$values", seasonsData) ).execute()).join().getStatus().expectSuccess("upsert problem"); @@ -174,7 +174,7 @@ private void upsertTablesData() { // Upsert list of series to episodes retryCtx.supplyResult(session -> session.createQuery( "UPSERT INTO episodes SELECT * FROM AS_TABLE($values)", - QueryTx.SERIALIZABLE_RW, + TxMode.SERIALIZABLE_RW, Params.of("$values", episodesData) ).execute()).join().getStatus().expectSuccess("upsert problem"); } @@ -185,7 +185,7 @@ private void upsertSimple() { + "VALUES (2, 6, 1, \"TBD\");"; // Executes data query with specified transaction control settings. - retryCtx.supplyResult(session -> session.createQuery(query, QueryTx.SERIALIZABLE_RW).execute()) + retryCtx.supplyResult(session -> session.createQuery(query, TxMode.SERIALIZABLE_RW).execute()) .join().getValue(); } @@ -196,7 +196,7 @@ private void selectSimple() { // Executes data query with specified transaction control settings. QueryReader result = retryCtx.supplyResult( - session -> QueryReader.readFrom(session.createQuery(query, QueryTx.SERIALIZABLE_RW)) + session -> QueryReader.readFrom(session.createQuery(query, TxMode.SERIALIZABLE_RW)) ).join().getValue(); logger.info("--[ SelectSimple ]--"); @@ -226,7 +226,7 @@ private void selectWithParams(long seriesID, long seasonID) { ); QueryReader result = retryCtx.supplyResult( - session -> QueryReader.readFrom(session.createQuery(query, QueryTx.SNAPSHOT_RO, params)) + session -> QueryReader.readFrom(session.createQuery(query, TxMode.SNAPSHOT_RO, params)) ).join().getValue(); logger.info("--[ SelectWithParams ] -- "); @@ -258,7 +258,7 @@ private void asyncSelectRead(long seriesID, long seasonID) { logger.info("--[ ExecuteAsyncQueryWithParams ]--"); retryCtx.supplyResult(session -> { - QueryStream asyncQuery = session.createQuery(query, QueryTx.SNAPSHOT_RO, params); + QueryStream asyncQuery = session.createQuery(query, TxMode.SNAPSHOT_RO, params); return asyncQuery.execute(part -> { ResultSetReader rs = part.getResultSetReader(); logger.info("read {} rows of result set {}", rs.getRowCount(), part.getResultSetIndex()); @@ -275,7 +275,7 @@ private void asyncSelectRead(long seriesID, long seasonID) { private void multiStepTransaction(long seriesID, long seasonID) { retryCtx.supplyStatus(session -> { - QueryTransaction transaction = session.createNewTransaction(QueryTx.SNAPSHOT_RO); + QueryTransaction transaction = session.createNewTransaction(TxMode.SNAPSHOT_RO); String query1 = "DECLARE $seriesId AS Uint64; " + "DECLARE $seasonId AS Uint64; " @@ -329,7 +329,7 @@ private void multiStepTransaction(long seriesID, long seasonID) { private void tclTransaction() { retryCtx.supplyResult(session -> { - QueryTransaction transaction = session.beginTransaction(QueryTx.SERIALIZABLE_RW) + QueryTransaction transaction = session.beginTransaction(TxMode.SERIALIZABLE_RW) .join().getValue(); String query @@ -351,11 +351,11 @@ private void tclTransaction() { } private void dropTables() { - retryCtx.supplyResult(session -> session.createQuery("DROP TABLE episodes;", QueryTx.NONE).execute()) + retryCtx.supplyResult(session -> session.createQuery("DROP TABLE episodes;", TxMode.NONE).execute()) .join().getStatus().expectSuccess("drop table episodes problem"); - retryCtx.supplyResult(session -> session.createQuery("DROP TABLE seasons;", QueryTx.NONE).execute()) + retryCtx.supplyResult(session -> session.createQuery("DROP TABLE seasons;", TxMode.NONE).execute()) .join().getStatus().expectSuccess("drop table seasons problem"); - retryCtx.supplyResult(session -> session.createQuery("DROP TABLE series;", QueryTx.NONE).execute()) + retryCtx.supplyResult(session -> session.createQuery("DROP TABLE series;", TxMode.NONE).execute()) .join().getStatus().expectSuccess("drop table series problem"); } diff --git a/ydb-cookbook/src/main/java/tech/ydb/examples/simple/ComplexTransaction.java b/ydb-cookbook/src/main/java/tech/ydb/examples/simple/ComplexTransaction.java index b269a70..16a8710 100644 --- a/ydb-cookbook/src/main/java/tech/ydb/examples/simple/ComplexTransaction.java +++ b/ydb-cookbook/src/main/java/tech/ydb/examples/simple/ComplexTransaction.java @@ -1,14 +1,15 @@ package tech.ydb.examples.simple; import java.time.Duration; -import tech.ydb.core.grpc.GrpcTransport; +import tech.ydb.common.transaction.TxMode; +import tech.ydb.core.grpc.GrpcTransport; import tech.ydb.examples.SimpleExample; import tech.ydb.table.Session; import tech.ydb.table.TableClient; import tech.ydb.table.description.TableDescription; import tech.ydb.table.query.DataQueryResult; -import tech.ydb.table.transaction.Transaction; +import tech.ydb.table.transaction.TableTransaction; import tech.ydb.table.transaction.TxControl; import tech.ydb.table.values.PrimitiveType; @@ -24,7 +25,7 @@ protected void run(GrpcTransport transport, String pathPrefix) { try ( TableClient tableClient = TableClient.newClient(transport).build(); - Session session = tableClient.createSession(Duration.ofSeconds(5)).join().getValue(); + Session session = tableClient.createSession(Duration.ofSeconds(5)).join().getValue() ) { session.dropTable(tablePath) @@ -40,22 +41,17 @@ protected void run(GrpcTransport transport, String pathPrefix) { .join() .expectSuccess("cannot create table"); - Transaction transaction = session.beginTransaction(Transaction.Mode.SERIALIZABLE_READ_WRITE) - .join() - .getValue(); + TableTransaction transaction = session.beginTransaction(TxMode.SERIALIZABLE_RW) + .join().getValue(); String query1 = "UPSERT INTO [" + tablePath + "] (key, value) VALUES (1, 'one');"; - DataQueryResult result1 = session.executeDataQuery(query1, TxControl.id(transaction)) - .join() - .getValue(); + DataQueryResult result1 = transaction.executeDataQuery(query1).join().getValue(); System.out.println("--[insert1]-------------------"); DataQueryResults.print(result1); System.out.println("------------------------------"); String query2 = "UPSERT INTO [" + tablePath + "] (key, value) VALUES (2, 'two');"; - DataQueryResult result2 = session.executeDataQuery(query2, TxControl.id(transaction)) - .join() - .getValue(); + DataQueryResult result2 = transaction.executeDataQuery(query2).join().getValue(); System.out.println("--[insert2]-------------------"); DataQueryResults.print(result2); System.out.println("------------------------------"); From 940b66c93b91568fb6fd2f533271fe60516ae147 Mon Sep 17 00:00:00 2001 From: Alexandr Gorshenin Date: Mon, 25 Mar 2024 14:34:28 +0000 Subject: [PATCH 08/12] Added complex transaction example to tests --- .../ydb/examples/simple/ComplexTransaction.java | 13 +++++++++---- .../test/java/tech/ydb/examples/ExamplesTest.java | 6 ++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/ydb-cookbook/src/main/java/tech/ydb/examples/simple/ComplexTransaction.java b/ydb-cookbook/src/main/java/tech/ydb/examples/simple/ComplexTransaction.java index 16a8710..47cd292 100644 --- a/ydb-cookbook/src/main/java/tech/ydb/examples/simple/ComplexTransaction.java +++ b/ydb-cookbook/src/main/java/tech/ydb/examples/simple/ComplexTransaction.java @@ -44,19 +44,19 @@ protected void run(GrpcTransport transport, String pathPrefix) { TableTransaction transaction = session.beginTransaction(TxMode.SERIALIZABLE_RW) .join().getValue(); - String query1 = "UPSERT INTO [" + tablePath + "] (key, value) VALUES (1, 'one');"; + String query1 = "UPSERT INTO `" + tablePath + "` (key, value) VALUES (1, 'one');"; DataQueryResult result1 = transaction.executeDataQuery(query1).join().getValue(); System.out.println("--[insert1]-------------------"); DataQueryResults.print(result1); System.out.println("------------------------------"); - String query2 = "UPSERT INTO [" + tablePath + "] (key, value) VALUES (2, 'two');"; + String query2 = "UPSERT INTO `" + tablePath + "` (key, value) VALUES (2, 'two');"; DataQueryResult result2 = transaction.executeDataQuery(query2).join().getValue(); System.out.println("--[insert2]-------------------"); DataQueryResults.print(result2); System.out.println("------------------------------"); - String query3 = "SELECT * FROM [" + tablePath + "];"; + String query3 = "SELECT * FROM `" + tablePath + "`;"; DataQueryResult result3 = session.executeDataQuery(query3, TxControl.onlineRo().setCommitTx(true)) .join() .getValue(); @@ -68,7 +68,7 @@ protected void run(GrpcTransport transport, String pathPrefix) { .join() .expectSuccess("cannot commit transaction"); - String query = "SELECT * FROM [" + tablePath + "];"; + String query = "SELECT * FROM `" + tablePath + "`;"; DataQueryResult result = session.executeDataQuery(query, TxControl.onlineRo().setCommitTx(true)) .join() .getValue(); @@ -81,4 +81,9 @@ protected void run(GrpcTransport transport, String pathPrefix) { public static void main(String[] args) { new ComplexTransaction().doMain(args); } + + public static int test(String[] args) { + new ComplexTransaction().doMain(args); + return 0; + } } diff --git a/ydb-cookbook/src/test/java/tech/ydb/examples/ExamplesTest.java b/ydb-cookbook/src/test/java/tech/ydb/examples/ExamplesTest.java index 38fc4c8..98c5d6b 100644 --- a/ydb-cookbook/src/test/java/tech/ydb/examples/ExamplesTest.java +++ b/ydb-cookbook/src/test/java/tech/ydb/examples/ExamplesTest.java @@ -7,6 +7,7 @@ import tech.ydb.examples.batch_upload.BatchUpload; import tech.ydb.examples.bulk_upsert.BulkUpsert; import tech.ydb.examples.pagination.PaginationApp; +import tech.ydb.examples.simple.ComplexTransaction; import tech.ydb.examples.simple.ReadTableExample; import tech.ydb.test.junit5.YdbHelperExtension; @@ -52,4 +53,9 @@ public void testReadTable() { public void testPagination() { Assertions.assertEquals(0, PaginationApp.test(args(), "Pagination test")); } + + @Test + public void testComplexTransaction() { + Assertions.assertEquals(0, ComplexTransaction.test(connectionString())); + } } From 642d971a189e13b4df7eaf37fd51f431629a119c Mon Sep 17 00:00:00 2001 From: Alexandr Gorshenin Date: Thu, 28 Mar 2024 10:33:52 +0000 Subject: [PATCH 09/12] Upgrade SDK version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a72253..1655ee9 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ 2.22.1 1.82 - 2.2.0-SNAPSHOT + 2.2.0 From 75507446bda6f322a9edd58282b4315050911e0f Mon Sep 17 00:00:00 2001 From: Alexandr Gorshenin Date: Thu, 28 Mar 2024 10:37:07 +0000 Subject: [PATCH 10/12] Upgrade pgjdbc version to avoid vulnerable --- jdbc/spring-data-jpa-v5/pom.xml | 2 +- jdbc/spring-data-jpa/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jdbc/spring-data-jpa-v5/pom.xml b/jdbc/spring-data-jpa-v5/pom.xml index d72b3dc..3299cc8 100644 --- a/jdbc/spring-data-jpa-v5/pom.xml +++ b/jdbc/spring-data-jpa-v5/pom.xml @@ -57,7 +57,7 @@ org.postgresql postgresql - 42.7.1 + 42.7.3 org.testcontainers diff --git a/jdbc/spring-data-jpa/pom.xml b/jdbc/spring-data-jpa/pom.xml index d883b09..1be2214 100644 --- a/jdbc/spring-data-jpa/pom.xml +++ b/jdbc/spring-data-jpa/pom.xml @@ -58,7 +58,7 @@ org.postgresql postgresql - 42.7.1 + 42.7.3 org.testcontainers From 48f79737b03c5d5f92210b4f29d6f46796a10e30 Mon Sep 17 00:00:00 2001 From: Alexandr Gorshenin Date: Thu, 28 Mar 2024 10:39:54 +0000 Subject: [PATCH 11/12] Update github actions --- .github/workflows/build.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 0c8fe7d..643e1d7 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -6,7 +6,7 @@ on: - master - develop pull_request: - type: [opened, reopened, edited] + type: [opened, reopened, edited, synchronize] jobs: build: @@ -44,7 +44,7 @@ jobs: - name: Checkout YDB Java SDK if: ${{ env.NEED_SDK }} - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: ydb-platform/ydb-java-sdk ref: develop @@ -61,7 +61,7 @@ jobs: - name: Checkout YDB YC Auth Provider if: ${{ env.NEED_SDK }} - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: ydb-platform/ydb-java-yc ref: develop From 59b6bc6c9e9c05131b9c3f656021d4af414a77ad Mon Sep 17 00:00:00 2001 From: Alexandr Gorshenin Date: Thu, 28 Mar 2024 10:54:56 +0000 Subject: [PATCH 12/12] Remove reducant dependecies --- basic_example/pom.xml | 4 ---- query-example/pom.xml | 4 ---- 2 files changed, 8 deletions(-) diff --git a/basic_example/pom.xml b/basic_example/pom.xml index 442407a..d69fe3b 100644 --- a/basic_example/pom.xml +++ b/basic_example/pom.xml @@ -21,10 +21,6 @@ tech.ydb ydb-sdk-table - - tech.ydb - ydb-sdk-topic - tech.ydb.auth yc-auth-provider diff --git a/query-example/pom.xml b/query-example/pom.xml index b95c969..42a68f9 100644 --- a/query-example/pom.xml +++ b/query-example/pom.xml @@ -21,10 +21,6 @@ tech.ydb ydb-sdk-query - - tech.ydb - ydb-sdk-topic - tech.ydb.auth yc-auth-provider