1、简介 {#1简介}
通过使用联机分析处理(Online Analytical Processing,OLAP),企业可以深入了解当前的运营情况,并确定改进趋势。这通常是通过对汇总的业务数据进行复杂的分析来实现的。
ClickHouse 是一个开源的、列式 OLAP 数据库,因其出色的 性能 而大受欢迎。
本文将带你了解如何在 Spring Boot 中整合、使用 ClickHouse。
2、项目设置 {#2项目设置}
在开始与 ClickHouse 数据库交互之前,我们需要添加一些 SDK 依赖,并正确配置我们的应用。
2.1、依赖 {#21依赖}
首先,在项目的 pom.xml
中添加必要的依赖:
<dependency>
<groupId>com.clickhouse</groupId>
<artifactId>clickhouse-jdbc</artifactId>
<version>0.7.1</version>
</dependency>
<dependency>
<groupId>org.lz4</groupId>
<artifactId>lz4-java</artifactId>
<version>1.8.0</version>
</dependency>
clickhouse-jdbc 依赖提供了 JDBC API 的实现,使我们能够与 ClickHouse 数据库建立连接并进行交互。
默认情况下,ClickHouse 使用 LZ4 压缩来存储数据,为此我们添加了 lz4-java 依赖项。
2.2、使用 Flyway 定义数据表 {#22使用-flyway-定义数据表}
接下来,定义数据库表,并对其执行操作。
使用 Flyway 来管理数据库迁移。这需要添加 flyway-core
和 flyway-database-clickhouse
依赖:
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-clickhouse</artifactId>
<version>10.16.3</version>
</dependency>
将这些依赖添加到 pom.xml
之后,在 src/main/resources/db/migration
目录中创建一个名为 V001__create_table.sql
的迁移脚本,内容如下:
CREATE TABLE authors (
id UUID,
name String,
email String,
created_at DateTime
)
ENGINE = MergeTree()
PRIMARY KEY id;
上面的脚本创建了一个以 id
为主键的 authors
表,并创建了其他几列。我们使用 MergeTree
表 引擎,该引擎对插入和查询性能进行了优化。
2.3、Data Model {#23data-model}
最后,创建一个 Author
record
,表示 authors
表中的数据:
public record Author(
UUID id,
String name,
String email,
LocalDateTime createdAt) {
public static Author create(String name, String email) {
return new Author(
UUID.randomUUID(),
name,
email,
LocalDateTime.now()
);
}
}
我们还添加了一个静态 create()
方法,使用随机 UUID
和当前时间戳实例化 Author
record
。
3、使用 Testcontainers 设置本地测试环境 {#3使用-testcontainers-设置本地测试环境}
为了便于本地开发和测试,我们使用 Testcontainers 来建立 ClickHouse 数据库。
通过 Testcontainers 运行数据库的前提条件是有一个活动的 Docker 实例。
3.1、测试所需的依赖 {#31测试所需的依赖}
首先,在 pom.xml
中添加必要的测试依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>clickhouse</artifactId>
<scope>test</scope>
</dependency>
spring-boot-testcontainers 和 clickhouse-testcontainers 模块的依赖提供了所需的类,用于为我们的 ClickHouse 数据库启动一个临时的 Docker 实例。
3.2、定义 Testcontainers Bean {#32定义-testcontainers-bean}
接下来,创建一个 @TestConfiguration
类来定义 Testcontainers
Bean:
@TestConfiguration(proxyBeanMethods = false)
class TestcontainersConfiguration {
@Bean
public ClickHouseContainer clickhouseContainer() {
return new ClickHouseContainer("clickhouse/clickhouse-server:24.11");
}
@Bean
public DynamicPropertyRegistrar dynamicPropertyRegistrar(ClickHouseContainer clickhouseContainer) {
return registry -> {
registry.add("spring.datasource.url", clickhouseContainer::getJdbcUrl);
registry.add("spring.datasource.username", clickhouseContainer::getUsername);
registry.add("spring.datasource.password", clickhouseContainer::getPassword);
registry.add("spring.datasource.driver-class-name", clickhouseContainer::getDriverClassName);
};
}
}
在创建 ClickHouseContainer
Bean 时,我们指定了 ClickHouse 镜像的最新稳定版本。
然后,我们定义一个 DynamicPropertyRegistrar
Bean 来配置必要的数据源属性。这样,我们的应用就可以连接到 ClickHouse 数据库容器。
在配置了正确的连接详细信息后,Spring Boot 会自动创建一个 JdbcTemplate
Bean(稍后会用到)。
3.3、在开发过程中使用 Testcontainers {#33在开发过程中使用-testcontainers}
虽然 Testcontainers 主要用于集成测试,但我们也可以在本地开发过程中使用它。
为此,需要在 src/test/java
目录中创建一个单独的 main 类:
class TestApplication {
public static void main(String[] args) {
SpringApplication.from(Application::main)
.with(TestcontainersConfiguration.class)
.run(args);
}
}
如上,我们创建了一个 TestApplication
类,并在其 main()
方法中使用 TestcontainersConfiguration
类启动我们的 Application
类。
这种设置可帮助我们在本地设置和管理外部服务。我们可以运行 Spring Boot 应用,让它连接到通过 Testcontainers 启动的外部服务。
4、执行 CRUD 操作 {#4执行-crud-操作}
本地环境就绪后,让我们使用 JdbcTemplate
Bean 与 authors
表进行交互:
Author author = Author.create("John Doe", "doe.john@baeldung.com");
jdbcTemplate.update(
"""
INSERT INTO authors (id, name, email, created_at)
VALUES (?, ?, ?, ?);
""",
author.id(),
author.name(),
author.email(),
author.createdAt()
);
如上,我们使用 create()
方法创建一个新的 Author
实例,然后使用 JdbcTemplate
的 update()
方法将其插入 authors
表。
为了验证 author
record
是否已成功保存,再用它的 id
执行一次读取查询:
List<Author> retrievedAuthors = jdbcTemplate.query(
"SELECT * FROM authors WHERE id = ?",
(ResultSet resultSet, int rowNum) -> new Author(
UUID.fromString(resultSet.getString("id")),
resultSet.getString("name"),
resultSet.getString("email"),
resultSet.getObject("created_at", LocalDateTime.class)
),
author.id()
);
assertThat(retrievedAuthors)
.hasSize(1)
.first()
.satisfies(retrievedAuthor -> {
assertThat(retrievedAuthor.id()).isEqualTo(author.id());
assertThat(retrievedAuthor.name()).isEqualTo(author.name());
assertThat(retrievedAuthor.email()).isEqualTo(author.email());
assertThat(retrievedAuthor.createdAt()).isNotNull();
});
我们使用 JdbcTemplate
的 query()
方法按 id
检索已保存的 author
record,并断言检索到的 Author
与我们之前保存的 Author
一致。
出于演示目的,这里只演示了保存和读取操作。你可以参考 ClickHouse 提供的 SQL 参考文档 来进一步了解其语法和操作符。
5、总结 {#5总结}
本文介绍了如何在 Spring Boot 中整合、使用 ClickHouse,以及如何通过 Testcontainers 启动临时的 Clickhouse Docker 实例来进行测试。
Ref:https://www.baeldung.com/spring-boot-olap-clickhouse-database