From 731995427835890a636d4a6f493eeced14fc3be7 Mon Sep 17 00:00:00 2001 From: Polyglot AI <293096396+polyglotAI-bot@users.noreply.github.com> Date: Wed, 14 Oct 2026 15:55:57 +0000 Subject: [PATCH] [examples] Remove old Spring example demo-service examples/demo-spring-service (added in #3096) replaces the old examples/demo-service Spring Boot example. Remove the old example and point the README and the client docs to the new one. Drop examples/demo-service/pom.xml from the example compile list in jvm-compatibility.yml. Without this change the weekly job fails because the POM file no longer exists. Closes #3111 Co-Authored-By: Claude Opus 5.5 --- .github/workflows/jvm-compatibility.yml | 1 - README.md | 2 +- docs/clickhouse-docs/client.mdx | 4 +- examples/demo-service/.gitignore | 32 --- examples/demo-service/README.md | 69 ------ examples/demo-service/pom.xml | 146 ------------ .../demo_service/BasicObjectsPool.java | 38 --- .../demo_service/CalculationResult.java | 18 -- .../demo_service/DbConfiguration.java | 39 ---- .../demo_service/DemoServiceApplication.java | 13 -- .../demo_service/JPAInsertController.java | 54 ----- .../demo_service/MetricsConfig.java | 55 ----- .../ObjectsPreparedCollection.java | 50 ---- .../demo_service/QueryController.java | 217 ------------------ .../clickhouse/demo_service/data/UIEvent.java | 33 --- .../data/VirtualDatasetRecord.java | 26 --- .../jpa/ClickHouseStringArrayType.java | 71 ------ .../jpa/UIEventsDbRepository.java | 11 - .../src/main/resources/application.properties | 33 --- .../src/test/java/com/clickhouse/.keep | 0 history/latest/3111.md | 4 + 21 files changed, 7 insertions(+), 909 deletions(-) delete mode 100644 examples/demo-service/.gitignore delete mode 100644 examples/demo-service/README.md delete mode 100644 examples/demo-service/pom.xml delete mode 100644 examples/demo-service/src/main/java/com/clickhouse/demo_service/BasicObjectsPool.java delete mode 100644 examples/demo-service/src/main/java/com/clickhouse/demo_service/CalculationResult.java delete mode 100644 examples/demo-service/src/main/java/com/clickhouse/demo_service/DbConfiguration.java delete mode 100644 examples/demo-service/src/main/java/com/clickhouse/demo_service/DemoServiceApplication.java delete mode 100644 examples/demo-service/src/main/java/com/clickhouse/demo_service/JPAInsertController.java delete mode 100644 examples/demo-service/src/main/java/com/clickhouse/demo_service/MetricsConfig.java delete mode 100644 examples/demo-service/src/main/java/com/clickhouse/demo_service/ObjectsPreparedCollection.java delete mode 100644 examples/demo-service/src/main/java/com/clickhouse/demo_service/QueryController.java delete mode 100644 examples/demo-service/src/main/java/com/clickhouse/demo_service/data/UIEvent.java delete mode 100644 examples/demo-service/src/main/java/com/clickhouse/demo_service/data/VirtualDatasetRecord.java delete mode 100644 examples/demo-service/src/main/java/com/clickhouse/demo_service/jpa/ClickHouseStringArrayType.java delete mode 100644 examples/demo-service/src/main/java/com/clickhouse/demo_service/jpa/UIEventsDbRepository.java delete mode 100644 examples/demo-service/src/main/resources/application.properties delete mode 100644 examples/demo-service/src/test/java/com/clickhouse/.keep create mode 100644 history/latest/3111.md diff --git a/.github/workflows/jvm-compatibility.yml b/.github/workflows/jvm-compatibility.yml index 5e4036494..26e5c64e7 100644 --- a/.github/workflows/jvm-compatibility.yml +++ b/.github/workflows/jvm-compatibility.yml @@ -150,7 +150,6 @@ jobs: examples/client-v2-apache-arrow/pom.xml examples/client-v2-json-processors/pom.xml examples/demo-kotlin-service/pom.xml - examples/demo-service/pom.xml examples/jdbc-v2-json-processors/pom.xml ) fi diff --git a/README.md b/README.md index a8dba8907..38a32dd53 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Nightly Builds: https://s01.oss.sonatype.org/content/repositories/snapshots/com/ [Begin-with Usage Examples](../../tree/main/examples/client-v2) -[Spring Demo Service](https://github.com/ClickHouse/clickhouse-java/tree/main/examples/demo-service) +[Spring Demo Service](https://github.com/ClickHouse/clickhouse-java/tree/main/examples/demo-spring-service) ## JDBC Driver diff --git a/docs/clickhouse-docs/client.mdx b/docs/clickhouse-docs/client.mdx index 8b7185fc5..b408ed64a 100644 --- a/docs/clickhouse-docs/client.mdx +++ b/docs/clickhouse-docs/client.mdx @@ -825,7 +825,7 @@ This object should be closed as soon as possible to release a connection because ### Examples {#examples} - Example code is available in [repo](https://github.com/ClickHouse/clickhouse-java/tree/main/examples/client-v2) -- Reference Spring Service [implementation](https://github.com/ClickHouse/clickhouse-java/tree/main/examples/demo-service) +- Reference Spring Service [implementation](https://github.com/ClickHouse/clickhouse-java/tree/main/examples/demo-spring-service) ## Common API {#common-api} @@ -898,7 +898,7 @@ client.register(ArticleViewEvent.class, client.getTableSchema(TABLE_NAME)); Complete examples code is stored in the repo in a 'example` [folder](https://github.com/ClickHouse/clickhouse-java/tree/main/examples): - [client-v2](https://github.com/ClickHouse/clickhouse-java/tree/main/examples/client-v2) - main set of examples. -- [demo-service](https://github.com/ClickHouse/clickhouse-java/tree/main/examples/demo-service) - example of how to use the client in a Spring Boot application. +- [demo-spring-service](https://github.com/ClickHouse/clickhouse-java/tree/main/examples/demo-spring-service) - example of how to use the client and the JDBC driver in a Spring Boot application, with observability. - [demo-kotlin-service](https://github.com/ClickHouse/clickhouse-java/tree/main/examples/demo-kotlin-service) - example of how to use the client in Ktor (Kotlin) application. ## Reading Data {#reading-data} diff --git a/examples/demo-service/.gitignore b/examples/demo-service/.gitignore deleted file mode 100644 index 228daac5e..000000000 --- a/examples/demo-service/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -# Maven build output -target/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ - -### VS Code ### -.vscode/ diff --git a/examples/demo-service/README.md b/examples/demo-service/README.md deleted file mode 100644 index 8c76c3191..000000000 --- a/examples/demo-service/README.md +++ /dev/null @@ -1,69 +0,0 @@ -# ClickHouse-Java Demo Service - -## About -This is an example of a Spring Boot service using ClickHouse client directly and via JPA. -Example is an application that requires ClickHouse DB running externally. It can be a Docker or -ClickHouse Cloud instance. - -## How to Run - -### Initialize DB -Set up a ClickHouse instance. - -Example of running with Docker: -```shell -docker run -d --name demo-service-db -e CLICKHOUSE_USER=default -e CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT=1 -e CLICKHOUSE_PASSWORD=secret\ - -p 8123:8123 clickhouse/clickhouse-server - -docker ps -# output should be like: -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -2abfefc40a84 clickhouse/clickhouse-server "/entrypoint.sh" 4 seconds ago Up 2 seconds 9000/tcp, 0.0.0.0:8123->8123/tcp, :::8123->8123/tcp, 9009/tcp demo-service-db -``` - -Example how to run client: -```shell -docker exec -it demo-service-db clickhouse-client -``` - -Create table (needed for JPA example): -``` -CREATE TABLE ui_events -( - `id` String, - `timestamp` DateTime64, - `event_name` String, - `tags` Array(String) -) -ENGINE = MergeTree -ORDER BY timestamp -``` - -### Run Demo-Service - -```shell -mvn spring-boot:run -``` - -### Interact with API - -#### Direct Client - -To read `limit` number of rows from `system.numbers`: -```shell -curl http://localhost:8080/direct/dataset/0?limit=100000 -``` - -#### JPA - -To insert some data: -```shell -curl -v -X POST -H "Content-Type: application/json" \ - -d '{"id": "4NAD7B8HH1", "timestamp": "2025-04-07T14:30:00.000Z", "eventName": "Login", "tags": ["security", "activity"]}'\ - http://localhost:8080/events/ui_events -``` - -To fetch inserted data: -```shell -curl -v -X GET http://localhost:8080/events/ui_events -``` \ No newline at end of file diff --git a/examples/demo-service/pom.xml b/examples/demo-service/pom.xml deleted file mode 100644 index d96c1fa7f..000000000 --- a/examples/demo-service/pom.xml +++ /dev/null @@ -1,146 +0,0 @@ - - - 4.0.0 - - - org.springframework.boot - spring-boot-starter-parent - 3.4.4 - - - - com.clickhouse - demo-service - 0.0.1-SNAPSHOT - jar - - ClickHouse Java Demo Service - Spring Boot service using the ClickHouse client directly and via JPA - https://github.com/ClickHouse/clickhouse-java - 2026 - - - ClickHouse, Inc. - https://clickhouse.com/ - - - - - The Apache Software License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0 - repo - - - - - https://github.com/ClickHouse/clickhouse-java - scm:git@github.com:ClickHouse/clickhouse-java.git - scm:git@github.com:ClickHouse/clickhouse-java.git - HEAD - - - - - - ossrh - Sonatype OSSRH - https://central.sonatype.com/repository/maven-snapshots/ - - false - - - true - - - - - - 2026 - 17 - - 0.12.0-rc1-SNAPSHOT - all - 1.18.42 - 1.14.3 - - - - - com.clickhouse - clickhouse-jdbc - ${clickhouse-java.version} - ${clickhouse-packages.classifier} - - - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.boot - spring-boot-starter-web - - - - - org.springframework.boot - spring-boot-starter-data-jpa - - - - org.projectlombok - lombok - provided - - - - io.micrometer - micrometer-core - ${micrometer.version} - - - - - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.platform - junit-platform-launcher - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - - org.projectlombok - lombok - ${lombok.version} - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - - diff --git a/examples/demo-service/src/main/java/com/clickhouse/demo_service/BasicObjectsPool.java b/examples/demo-service/src/main/java/com/clickhouse/demo_service/BasicObjectsPool.java deleted file mode 100644 index 6a1d94838..000000000 --- a/examples/demo-service/src/main/java/com/clickhouse/demo_service/BasicObjectsPool.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.clickhouse.demo_service; - -import java.util.Deque; - -/** - * Very basic object pool implementation. - * It uses a deque to store objects. Leased objects are removed from the - * deque and released objects are added back to the deque. When there is no objects in the deque, - * a new object is created (assuming it will be returned on release). - * - * @param - */ -public abstract class BasicObjectsPool { - - private Deque objects; - - BasicObjectsPool(Deque objects) { - this(objects, 0); - } - - BasicObjectsPool(Deque objects, int size) { - this.objects = objects; - for (int i = 0; i < size; i++) { - this.objects.add(create()); - } - } - - public T lease() { - T obj = objects.poll(); - return obj != null ? obj : create(); - } - - public void release(T obj) { - objects.addFirst(obj); - } - - abstract T create(); -} diff --git a/examples/demo-service/src/main/java/com/clickhouse/demo_service/CalculationResult.java b/examples/demo-service/src/main/java/com/clickhouse/demo_service/CalculationResult.java deleted file mode 100644 index f65bd9f3a..000000000 --- a/examples/demo-service/src/main/java/com/clickhouse/demo_service/CalculationResult.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.clickhouse.demo_service; - -public class CalculationResult { - - long p1; - - public CalculationResult(long p1) { - this.p1 = p1; - } - - public long getP1() { - return p1; - } - - public void setP1(long p1) { - this.p1 = p1; - } -} diff --git a/examples/demo-service/src/main/java/com/clickhouse/demo_service/DbConfiguration.java b/examples/demo-service/src/main/java/com/clickhouse/demo_service/DbConfiguration.java deleted file mode 100644 index a81a7c535..000000000 --- a/examples/demo-service/src/main/java/com/clickhouse/demo_service/DbConfiguration.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.clickhouse.demo_service; - - -import com.clickhouse.client.api.Client; -import io.micrometer.core.instrument.MeterRegistry; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; -import org.springframework.transaction.annotation.EnableTransactionManagement; - -@Configuration -@EnableJpaRepositories -@EnableTransactionManagement -public class DbConfiguration { - - @Bean - public Client chDirectClient(MeterRegistry meterRegistry, @Value("${db.url}") String dbUrl, @Value("${db.user}") String dbUser, - @Value("${db.pass}") String dbPassword) { - return new Client.Builder() - .addEndpoint(dbUrl) - .setUsername(dbUser) - .setPassword(dbPassword) - - // sets the maximum number of connections to the server at a time - // this is important for services handling many concurrent requests to ClickHouse - .setMaxConnections(100) - .setLZ4UncompressedBufferSize(1058576) - .setSocketRcvbuf(500_000) - .setSocketTcpNodelay(true) - .setSocketSndbuf(500_000) - .setClientNetworkBufferSize(500_000) - .allowBinaryReaderToReuseBuffers(true) // using buffer pool for binary reader - .registerClientMetrics(meterRegistry, "clickhouse-client-metrics") - .build(); - } - - // JPA configured via application.properties -} diff --git a/examples/demo-service/src/main/java/com/clickhouse/demo_service/DemoServiceApplication.java b/examples/demo-service/src/main/java/com/clickhouse/demo_service/DemoServiceApplication.java deleted file mode 100644 index 13ee025f1..000000000 --- a/examples/demo-service/src/main/java/com/clickhouse/demo_service/DemoServiceApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.clickhouse.demo_service; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class DemoServiceApplication { - - public static void main(String[] args) { - SpringApplication.run(DemoServiceApplication.class, args); - } - -} diff --git a/examples/demo-service/src/main/java/com/clickhouse/demo_service/JPAInsertController.java b/examples/demo-service/src/main/java/com/clickhouse/demo_service/JPAInsertController.java deleted file mode 100644 index 80c0012dc..000000000 --- a/examples/demo-service/src/main/java/com/clickhouse/demo_service/JPAInsertController.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.clickhouse.demo_service; - -import com.clickhouse.demo_service.data.UIEvent; -import com.clickhouse.demo_service.jpa.UIEventsDbRepository; -import jakarta.annotation.PostConstruct; -import jakarta.persistence.EntityManager; -import jakarta.transaction.Transactional; -import lombok.extern.java.Log; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.transaction.support.TransactionTemplate; -import org.springframework.web.bind.annotation.*; - -import java.util.Collection; - -/** - * Class demonstrates usage of ClickHouse JDBC driver with JPA - * - */ -@RestController -@RequestMapping("/events/") -@Log -public class JPAInsertController { - - @Autowired - private UIEventsDbRepository uiEvents; - - @Autowired - private PlatformTransactionManager transactionManager; - - @Autowired - private EntityManager entityManager; - - private TransactionTemplate transactionTemplate; - - @PostConstruct - public void setUp() { - transactionTemplate = new TransactionTemplate(transactionManager); - } - - @PostMapping("/ui_events") - @Transactional(Transactional.TxType.NOT_SUPPORTED) - public void addUIEvent(@RequestBody UIEvent event) { - // do input validation and conversion - transactionTemplate.executeWithoutResult(transactionStatus -> { - entityManager.persist(event); - }); - } - - @GetMapping("/ui_events") - public Collection lastUIEvents() { - return uiEvents.findAll(); - } -} diff --git a/examples/demo-service/src/main/java/com/clickhouse/demo_service/MetricsConfig.java b/examples/demo-service/src/main/java/com/clickhouse/demo_service/MetricsConfig.java deleted file mode 100644 index ba30ba589..000000000 --- a/examples/demo-service/src/main/java/com/clickhouse/demo_service/MetricsConfig.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.clickhouse.demo_service; -import io.micrometer.core.instrument.Clock; -import io.micrometer.core.instrument.logging.LoggingMeterRegistry; -import io.micrometer.core.instrument.logging.LoggingRegistryConfig; -import io.micrometer.core.instrument.simple.SimpleMeterRegistry; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Condition; -import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.Configuration; - -import java.time.Duration; - -@Configuration -public class MetricsConfig { - - // Define a simple config for the logging registry - @Bean - public LoggingRegistryConfig loggingRegistryConfig() { - return new LoggingRegistryConfig() { - @Override - public String get(String key) { - // Only "step" is required. Returning null for others means defaults will be used. - if ("step".equals(key)) { - return "35s"; // Publish metrics every 5 seconds - } - return null; - } - - @Override - public Duration step() { - return Duration.ofSeconds(5); - } - }; - } - - // Create the LoggingMeterRegistry bean. - @Bean - @ConditionalOnProperty("app.log_metrics") - public LoggingMeterRegistry loggingMeterRegistry(LoggingRegistryConfig config) { - LoggingMeterRegistry registry = new LoggingMeterRegistry(config, Clock.SYSTEM); - // Start the registry’s internal scheduler so that metrics are published periodically. - registry.start(); - return registry; - } - - @Bean - @ConditionalOnProperty(value = "app.log_metrics", havingValue = "false") - public SimpleMeterRegistry simpleMeterRegistry() { - SimpleMeterRegistry registry = new SimpleMeterRegistry(); - - return registry; - } -} diff --git a/examples/demo-service/src/main/java/com/clickhouse/demo_service/ObjectsPreparedCollection.java b/examples/demo-service/src/main/java/com/clickhouse/demo_service/ObjectsPreparedCollection.java deleted file mode 100644 index 1d0451cdb..000000000 --- a/examples/demo-service/src/main/java/com/clickhouse/demo_service/ObjectsPreparedCollection.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.clickhouse.demo_service; - -import java.util.Deque; -import java.util.Iterator; -import java.util.function.Supplier; - -/** - * This is a prepared collection of objects. It is aimed to solve the problem of - * creating and releasing objects in a loop. After all objects are used, the collection - * should be reset. - * - * - * @param - */ -public abstract class ObjectsPreparedCollection implements Supplier { - - private Deque objects; - - private Iterator iterator; - - ObjectsPreparedCollection(Deque objects) { - this(objects, 0); - } - - ObjectsPreparedCollection(Deque objects, int size) { - this.objects = objects; - for (int i = 0; i < size; i++) { - this.objects.add(create()); - } - this.reset(); - } - - @Override - public T get() { - T obj; - if (iterator.hasNext()) { - obj = iterator.next(); - } else { - obj = create(); - objects.addFirst(obj); - } - - return obj; - } - - public void reset() { - this.iterator = objects.iterator(); - } - abstract T create(); -} diff --git a/examples/demo-service/src/main/java/com/clickhouse/demo_service/QueryController.java b/examples/demo-service/src/main/java/com/clickhouse/demo_service/QueryController.java deleted file mode 100644 index 684c667a6..000000000 --- a/examples/demo-service/src/main/java/com/clickhouse/demo_service/QueryController.java +++ /dev/null @@ -1,217 +0,0 @@ -package com.clickhouse.demo_service; - - -import com.clickhouse.client.api.Client; -import com.clickhouse.client.api.data_formats.ClickHouseBinaryFormatReader; -import com.clickhouse.client.api.metadata.TableSchema; -import com.clickhouse.client.api.metrics.ClientMetrics; -import com.clickhouse.client.api.query.QueryResponse; -import com.clickhouse.client.api.query.QuerySettings; -import com.clickhouse.data.ClickHouseFormat; -import com.clickhouse.demo_service.data.VirtualDatasetRecord; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.MappingIterator; -import com.fasterxml.jackson.databind.json.JsonMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import jakarta.annotation.PostConstruct; -import jakarta.servlet.http.HttpServletResponse; -import lombok.extern.java.Log; -import org.springframework.web.bind.annotation.*; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.ConcurrentLinkedDeque; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -/** - * Class demonstrates using ClickHouse client directly from a service. - * It avoids JDBC overhead and much easier to use. - * Data may be streamed from database directly to the service response. - */ -@RestController -@RequestMapping("/dataset") -@Log -public class QueryController { - - private final Client chDirectClient; - - private static final int MAX_LIMIT = 100_000; - - private BasicObjectsPool> pool; - - public QueryController(Client chDirectClient) { - this.chDirectClient = chDirectClient; - } - - public TableSchema datasetQuerySchema; - - @PostConstruct - public void setup() { - chDirectClient.ping(3000); // helps to warm up the connection - - // Register class for deserialization - datasetQuerySchema = chDirectClient.getTableSchemaFromQuery(DATASET_QUERY); - chDirectClient.register(VirtualDatasetRecord.class, datasetQuerySchema); - log.info("Dataset schema: " + datasetQuerySchema.getColumns()); - - pool = new BasicObjectsPool<>(new ConcurrentLinkedDeque<>(), 100) { - @Override - ObjectsPreparedCollection create() { - return new ObjectsPreparedCollection<>(new LinkedList<>(), MAX_LIMIT) { - @Override - VirtualDatasetRecord create() { - return new VirtualDatasetRecord(); - } - }; - } - }; - } - - /** - * Makes query to a {@code system.numbers} that can be used to generate a virtual dataset. - * Size of the dataset is limited by the {@code limit} parameter. - */ - private static final String DATASET_QUERY = - "SELECT generateUUIDv4() as id, " + - "toUInt32(number) as p1, " + - "number, " + - "toFloat32(number/100000) as p2, " + - "toFloat64(number/100000) as p3" + - " FROM system.numbers"; - - /** - * Fetches data from a DB using row binary reader. VirtualDatasetRecord objects are created on each iteration and - * filled with data from the reader. Gives full control on how data is processed and stored. - * If this method returns a lot of data it may cause application slowdown. - * - * @param limit - * @return - */ - @GetMapping("/reader") - public List directDatasetFetch(@RequestParam(name = "limit", required = false) Integer limit) { - limit = limit == null ? 100 : limit; - - final String query = DATASET_QUERY + " LIMIT " + limit; - try (QueryResponse response = chDirectClient.query(query).get(3000, TimeUnit.MILLISECONDS)) { - ArrayList result = new ArrayList<>(); - - // iterable approach is more efficient for large datasets because it doesn't load all records into memory - ClickHouseBinaryFormatReader reader = chDirectClient.newBinaryFormatReader(response); - - long start = System.nanoTime(); - while (reader.next() != null) { - result.add(new VirtualDatasetRecord( - reader.getUUID("id"), - reader.getLong("p1"), - reader.getBigInteger("number"), - reader.getFloat("p2"), - reader.getDouble("p3") - )); - } - long duration = System.nanoTime() - start; - - // report metrics (only for demonstration purposes) - log.info(String.format("records: %d, read time: %d ms (%d bytes), client time: %d ms, server time: %d ms", - result.size(), TimeUnit.NANOSECONDS.toMillis(duration), response.getReadBytes(), - response.getMetrics().getMetric(ClientMetrics.OP_DURATION).getLong(), - TimeUnit.NANOSECONDS.toMillis(response.getServerTime()))); - - return result.stream().findFirst().stream().collect(Collectors.toCollection(ArrayList::new)); - } catch (Exception e) { - throw new RuntimeException("Failed to fetch dataset", e); - } - } - - private JsonMapper jsonMapper = new JsonMapper(); - - /** - * Reads data in JSONEachRow format, parses it into JSON library object (can be used for further processing) and - * writes it back to the response. - * This helps to reduce effort of writing data to the response. - * - * @param httpResp - * @param limit - */ - @GetMapping("/json_each_row_in_and_out") - @ResponseBody - public void directDataFetchJSONEachRow(HttpServletResponse httpResp, @RequestParam(name = "limit", required = false) Integer limit) { - limit = limit == null ? 100 : limit; - - final String query = DATASET_QUERY + " LIMIT " + limit; - QuerySettings settings = new QuerySettings().setFormat(ClickHouseFormat.JSONEachRow); - try (QueryResponse response = chDirectClient.query(query, settings).get(3000, TimeUnit.MILLISECONDS); - // JSONEachRow format is a stream of JSON objects, so we need to parse them one by one - MappingIterator jsonIter = jsonMapper.readerFor(ObjectNode.class) - .readValues(response.getInputStream())) { - httpResp.setContentType("application/json"); - JsonGenerator jsonGen = jsonMapper.getFactory().createGenerator(httpResp.getOutputStream()); - - jsonGen.writeStartArray(); - long start = System.nanoTime(); - int counter =0; - while (jsonIter.hasNext()) { - ObjectNode node = jsonIter.next(); - // here may be some processing logic - node.put("ordNum", counter++); - - } - jsonGen.writeEndArray(); - jsonGen.close(); - long duration = System.nanoTime() - start; - - // report metrics (only for demonstration purposes) - log.info(String.format("records: %d, read time: %d ms, client time: %d ms, server time: %d ms", - counter, TimeUnit.NANOSECONDS.toMillis(duration), - response.getMetrics().getMetric(ClientMetrics.OP_DURATION).getLong(), - TimeUnit.NANOSECONDS.toMillis(response.getServerTime()))); - } catch (Exception e) { - throw new RuntimeException("Failed to fetch dataset", e); - } - } - - /** - * Using POJO deserialization to fetch data from ClickHouse. - * If cache is enabled, objects are reused from the pool otherwise new objects are created on each iteration. - * - * @param limit - * @return - */ - @GetMapping("/read_to_pojo") - public CalculationResult directDatasetReadToPojo(@RequestParam(name = "limit", required = false) Integer limit, - @RequestParam(name = "cache", required = false) Boolean cache) { - limit = limit == null ? 100 : limit; - cache = cache != null && cache; - return readToPOJO(limit, cache); - } - - private CalculationResult readToPOJO(int limit, boolean cache) { - final String query = DATASET_QUERY + " LIMIT " + limit; - List result = null; - Supplier objectsPool = cache ? this.pool.lease() - : VirtualDatasetRecord::new; - try { - long start = System.nanoTime(); - - result = chDirectClient.queryAll(query, VirtualDatasetRecord.class, datasetQuerySchema, objectsPool); - long duration = System.nanoTime() - start; - log.info("records: " + result.size() + ", read time: " + TimeUnit.NANOSECONDS.toMillis(duration) + " ms"); - long p1Sum = 0; - for (VirtualDatasetRecord record : result) { - p1Sum += record.getP1(); - } - if (cache) { - ((ObjectsPreparedCollection) objectsPool).reset(); - } - return new CalculationResult(p1Sum); - } catch (Exception e) { - throw new RuntimeException("Failed to fetch dataset", e); - } finally { - if (cache) { - this.pool.release((ObjectsPreparedCollection) objectsPool); - } - } - } -} diff --git a/examples/demo-service/src/main/java/com/clickhouse/demo_service/data/UIEvent.java b/examples/demo-service/src/main/java/com/clickhouse/demo_service/data/UIEvent.java deleted file mode 100644 index 0a2403fcf..000000000 --- a/examples/demo-service/src/main/java/com/clickhouse/demo_service/data/UIEvent.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.clickhouse.demo_service.data; - -import com.clickhouse.demo_service.jpa.ClickHouseStringArrayType; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; -import lombok.Data; -import org.hibernate.annotations.Array; -import org.hibernate.annotations.JdbcType; -import org.hibernate.annotations.Type; -import org.hibernate.type.descriptor.jdbc.ArrayJdbcType; - -import java.sql.JDBCType; -import java.sql.Timestamp; -import java.util.Collection; -import java.util.List; - -@Entity -@Data -@Table(name = "ui_events") -public class UIEvent { - - @Id - private String id; - - private Timestamp timestamp; - - private String eventName; - - @JdbcType(ArrayJdbcType.class) - @Type(ClickHouseStringArrayType.class) - private Collection tags; -} diff --git a/examples/demo-service/src/main/java/com/clickhouse/demo_service/data/VirtualDatasetRecord.java b/examples/demo-service/src/main/java/com/clickhouse/demo_service/data/VirtualDatasetRecord.java deleted file mode 100644 index 1c75e39bf..000000000 --- a/examples/demo-service/src/main/java/com/clickhouse/demo_service/data/VirtualDatasetRecord.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.clickhouse.demo_service.data; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.ToString; - -import java.math.BigInteger; -import java.util.UUID; - -@Data -@AllArgsConstructor -@NoArgsConstructor -@ToString -public class VirtualDatasetRecord { - - private UUID id; - - private long p1; - - private BigInteger number; - - private float p2; - - private double p3; -} diff --git a/examples/demo-service/src/main/java/com/clickhouse/demo_service/jpa/ClickHouseStringArrayType.java b/examples/demo-service/src/main/java/com/clickhouse/demo_service/jpa/ClickHouseStringArrayType.java deleted file mode 100644 index 1f2b1f61a..000000000 --- a/examples/demo-service/src/main/java/com/clickhouse/demo_service/jpa/ClickHouseStringArrayType.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.clickhouse.demo_service.jpa; - -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.usertype.UserType; - -import java.io.Serializable; -import java.sql.*; -import java.util.*; - -public class ClickHouseStringArrayType implements UserType { - @Override - public int getSqlType() { - return Types.ARRAY; - } - - @Override - public Class returnedClass() { - return Collection.class; - } - - @Override - public boolean equals(Collection x, Collection y) { - return x.equals(y); - } - - @Override - public int hashCode(Collection x) { - return x.hashCode(); - } - - @Override - public Collection nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException { - // This implementation not optimal, but portable. - Array array = rs.getArray(position); - if (array != null) { - List list = new ArrayList<>(); - for (Object i : (Object[]) array.getArray() ) { - list.add(i); - } - return list; - } - return Collections.emptyList(); - } - - @Override - public void nullSafeSet(PreparedStatement st, Collection value, int index, SharedSessionContractImplementor session) throws SQLException { - st.setObject(index, value); - } - - @Override - public Collection deepCopy(Collection value) { - return new ArrayList(value); - } - - @Override - public boolean isMutable() { - // value should not be changed - return false; - } - - @Override - public Serializable disassemble(Collection value) { - return new ArrayList<>(value); - } - - @Override - public Collection assemble(Serializable cached, Object owner) { - return (Collection) cached; - } - -} diff --git a/examples/demo-service/src/main/java/com/clickhouse/demo_service/jpa/UIEventsDbRepository.java b/examples/demo-service/src/main/java/com/clickhouse/demo_service/jpa/UIEventsDbRepository.java deleted file mode 100644 index 044825c75..000000000 --- a/examples/demo-service/src/main/java/com/clickhouse/demo_service/jpa/UIEventsDbRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.clickhouse.demo_service.jpa; - -import com.clickhouse.demo_service.data.UIEvent; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import java.util.UUID; - -@Repository -public interface UIEventsDbRepository extends JpaRepository { -} diff --git a/examples/demo-service/src/main/resources/application.properties b/examples/demo-service/src/main/resources/application.properties deleted file mode 100644 index 0dfb1fba4..000000000 --- a/examples/demo-service/src/main/resources/application.properties +++ /dev/null @@ -1,33 +0,0 @@ -spring.application.name=demo-service - - -app.log_metrics=false -db.url=http://localhost:8123/default -db.user=default -db.pass=secret - - -spring.jpa.properties.hibernate.dialect=org.hibernate.annotations.processing.GenericDialect -spring.jpa.hibernate.connection.provider_class=com.zaxxer.hikari.hibernate.HikariConnectionProvider -spring.jpa.show-sql=true -spring.jpa.hibernate.ddl-auto=validate - -spring.datasource.url=jdbc:ch:http//${CH_ADDRESS:localhost:8123}/default -spring.datasource.username=${db.user} -spring.datasource.password=${db.pass} -spring.datasource.driver-class-name=com.clickhouse.jdbc.ClickHouseDriver - -spring.datasource.hikari.connection-timeout=30000 -spring.datasource.hikari.idle-timeout=20000 -spring.datasource.hikari.max-lifetime=300000 -spring.datasource.hikari.maximum-pool-size=100 -spring.datasource.hikari.minimum-idle=1 -spring.datasource.hikari.pool-name=ChConnPool -spring.datasource.hikari.connection-test-query=select 1 - -# To not throw exception on unsupported operations -spring.datasource.hikari.dataSourceProperties.jdbc_ignore_unsupported_values=true - - -logging.level.com.zaxxer.hikari.HikariConfig=DEBUG -logging.level.com.zaxxer.hikari=TRACE \ No newline at end of file diff --git a/examples/demo-service/src/test/java/com/clickhouse/.keep b/examples/demo-service/src/test/java/com/clickhouse/.keep deleted file mode 100644 index e69de29bb..000000000 diff --git a/history/latest/3111.md b/history/latest/3111.md new file mode 100644 index 000000000..e2c689cef --- /dev/null +++ b/history/latest/3111.md @@ -0,0 +1,4 @@ +- **[examples]** Removed the old `examples/demo-service` Spring Boot example. Use `examples/demo-spring-service` + instead: it shows the JDBC driver with Spring Data, Client V2, and observability in a Spring Boot service. The + README and the client docs now link to the new example. + (https://github.com/ClickHouse/clickhouse-java/issues/3111)